Skip to content

Commit cf8811b

Browse files
committed
Step 3
1 parent df20a08 commit cf8811b

File tree

7 files changed

+283
-211
lines changed

7 files changed

+283
-211
lines changed

codetracer-python-recorder/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
pub mod code_object;
88
mod logging;
9-
mod runtime_tracer;
9+
mod runtime;
1010
mod session;
1111
pub mod tracer;
1212

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use std::path::{Path, PathBuf};
2+
3+
use pyo3::Python;
4+
5+
use crate::code_object::CodeObjectWrapper;
6+
7+
/// Tracks activation gating for the runtime tracer. When configured with an
8+
/// activation path, tracing remains paused until code from that file starts
9+
/// executing. Once the activation window completes, tracing is disabled for the
10+
/// remainder of the session.
11+
#[derive(Debug)]
12+
pub struct ActivationController {
13+
activation_path: Option<PathBuf>,
14+
activation_code_id: Option<usize>,
15+
activation_done: bool,
16+
started: bool,
17+
}
18+
19+
impl ActivationController {
20+
pub fn new(activation_path: Option<&Path>) -> Self {
21+
let activation_path = activation_path
22+
.map(|p| std::path::absolute(p).expect("activation_path should resolve"));
23+
let started = activation_path.is_none();
24+
Self {
25+
activation_path,
26+
activation_code_id: None,
27+
activation_done: false,
28+
started,
29+
}
30+
}
31+
32+
pub fn is_active(&self) -> bool {
33+
self.started
34+
}
35+
36+
/// Return the canonical start path for writer initialisation.
37+
pub fn start_path<'a>(&'a self, fallback: &'a Path) -> &'a Path {
38+
self.activation_path.as_deref().unwrap_or(fallback)
39+
}
40+
41+
/// Attempt to transition into the active state. When the code object
42+
/// corresponds to the activation path, tracing becomes active and remembers
43+
/// the triggering code id so it can stop on return.
44+
pub fn ensure_started(&mut self, py: Python<'_>, code: &CodeObjectWrapper) {
45+
if self.started || self.activation_done {
46+
return;
47+
}
48+
if let Some(activation) = &self.activation_path {
49+
if let Ok(filename) = code.filename(py) {
50+
let file = Path::new(filename);
51+
// `CodeObjectWrapper::filename` is expected to return an absolute
52+
// path. If this assumption turns out to be wrong we will revisit
53+
// the comparison logic. Canonicalisation is deliberately avoided
54+
// here to limit syscalls on hot paths.
55+
if file == activation {
56+
self.started = true;
57+
self.activation_code_id = Some(code.id());
58+
log::debug!(
59+
"[RuntimeTracer] activated on enter: {}",
60+
activation.display()
61+
);
62+
}
63+
}
64+
}
65+
}
66+
67+
/// Handle return events and turn off tracing when the activation function
68+
/// exits. Returns `true` when tracing was deactivated by this call.
69+
pub fn handle_return(&mut self, code_id: usize) -> bool {
70+
if self.activation_code_id == Some(code_id) {
71+
self.started = false;
72+
self.activation_done = true;
73+
return true;
74+
}
75+
false
76+
}
77+
}

0 commit comments

Comments
 (0)