@@ -2,7 +2,24 @@ pub(crate) use decl::make_module;
22
33#[ pymodule( name = "faulthandler" ) ]
44mod 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