Skip to content

Commit 82b2a89

Browse files
committed
implement dump_traceback_later and cancel_dump_traceback_later
Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
1 parent 235adaf commit 82b2a89

File tree

1 file changed

+94
-1
lines changed

1 file changed

+94
-1
lines changed

stdlib/src/faulthandler.rs

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,24 @@ pub(crate) use decl::make_module;
22

33
#[pymodule(name = "faulthandler")]
44
mod decl {
5-
use crate::vm::{frame::Frame, function::OptionalArg, stdlib::sys::PyStderr, VirtualMachine};
5+
use crate::vm::{
6+
frame::{Frame, FrameRef},
7+
function::OptionalArg,
8+
stdlib::sys::PyStderr,
9+
VirtualMachine,
10+
};
11+
use rustpython_common::lock::PyRwLock;
12+
use std::io::Write;
13+
14+
struct FaultHandlerThread {
15+
enabled: bool,
16+
repeat: bool,
17+
exit: bool,
18+
timeout: std::time::Duration,
19+
frames: Vec<FrameRef>,
20+
}
21+
22+
static FAULT_HANDLER_THREAD: PyRwLock<Option<FaultHandlerThread>> = PyRwLock::new(None);
623

724
fn dump_frame(frame: &Frame, vm: &VirtualMachine) {
825
let stderr = PyStderr(vm);
@@ -29,6 +46,82 @@ mod decl {
2946
}
3047
}
3148

49+
#[pyfunction]
50+
fn dump_traceback_later(
51+
timeout: f32,
52+
repeat: OptionalArg<bool>,
53+
_file: OptionalArg<i32>,
54+
exit: OptionalArg<bool>,
55+
vm: &VirtualMachine,
56+
) {
57+
let timeout_duration = std::time::Duration::from_secs_f32(timeout);
58+
let repeat = repeat.unwrap_or(false);
59+
let exit = exit.unwrap_or(false);
60+
let frames = vm.frames.borrow().clone();
61+
let t_data = FaultHandlerThread {
62+
enabled: true,
63+
repeat,
64+
timeout: timeout_duration,
65+
frames,
66+
exit,
67+
};
68+
if let Some(t) = FAULT_HANDLER_THREAD.write().as_mut() {
69+
*t = t_data;
70+
} else {
71+
std::thread::spawn(move || {
72+
loop {
73+
let thread_info = FAULT_HANDLER_THREAD.read();
74+
let thread_info = match thread_info.as_ref() {
75+
Some(t) => t,
76+
None => return,
77+
};
78+
if !thread_info.enabled {
79+
*FAULT_HANDLER_THREAD.write() = None;
80+
return;
81+
}
82+
83+
std::thread::sleep(thread_info.timeout);
84+
85+
let thread_info = FAULT_HANDLER_THREAD.read();
86+
let thread_info = match thread_info.as_ref() {
87+
Some(t) => t,
88+
None => return,
89+
};
90+
if !thread_info.enabled {
91+
*FAULT_HANDLER_THREAD.write() = None;
92+
return;
93+
}
94+
for frame in thread_info.frames.iter() {
95+
// TODO: Fix
96+
let _ = writeln!(std::io::stderr(), "Stack (most recent call first):");
97+
let _ = writeln!(
98+
std::io::stderr(),
99+
" File \"{}\", line {} in {}",
100+
frame.code.source_path,
101+
frame.current_location().row.to_usize(),
102+
frame.code.obj_name
103+
);
104+
}
105+
if thread_info.exit {
106+
std::process::exit(1);
107+
}
108+
if !thread_info.repeat {
109+
*FAULT_HANDLER_THREAD.write() = None;
110+
return;
111+
}
112+
}
113+
});
114+
}
115+
}
116+
117+
#[pyfunction]
118+
fn cancel_dump_traceback_later() {
119+
FAULT_HANDLER_THREAD
120+
.write()
121+
.as_mut()
122+
.map(|t| t.enabled = false);
123+
}
124+
32125
#[derive(FromArgs)]
33126
#[allow(unused)]
34127
struct EnableArgs {

0 commit comments

Comments
 (0)