@@ -1050,6 +1050,7 @@ fn interrupt_random_kill_stress_test() {
10501050 let sandbox_wrapper = guard. sandbox_with_snapshot . as_mut ( ) . unwrap ( ) ;
10511051 let sandbox = & mut sandbox_wrapper. sandbox ;
10521052 let interrupt_handle = sandbox. interrupt_handle ( ) ;
1053+ let watchdog_handle = interrupt_handle. clone ( ) ;
10531054
10541055 // If we decided to kill, spawn a thread that will kill at a random time
10551056 // Use a barrier to ensure the killer thread waits until we're about to call the guest
@@ -1110,7 +1111,32 @@ fn interrupt_random_kill_stress_test() {
11101111 ) ;
11111112 }
11121113
1114+ // Watchdog: if the guest call doesn't return within 300s,
1115+ // force-kill it and print diagnostics.
1116+ let watchdog_thread_id = thread_id;
1117+ let watchdog_iteration = iteration;
1118+ let watchdog_should_kill = should_kill;
1119+ let watchdog_cancel = Arc :: new ( AtomicBool :: new ( false ) ) ;
1120+ let watchdog_cancel_clone = watchdog_cancel. clone ( ) ;
1121+ let watchdog = thread:: spawn ( move || {
1122+ for _ in 0 ..300 {
1123+ thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
1124+ if watchdog_cancel_clone. load ( Ordering :: Relaxed ) {
1125+ return ;
1126+ }
1127+ }
1128+ println ! (
1129+ "WATCHDOG: Thread {} iteration {} HUNG for 300s (should_kill={}), force-killing" ,
1130+ watchdog_thread_id, watchdog_iteration, watchdog_should_kill
1131+ ) ;
1132+ watchdog_handle. kill ( ) ;
1133+ } ) ;
1134+
11131135 let result = sandbox. call :: < u64 > ( "SpinForMs" , GUEST_CALL_DURATION_MS ) ;
1136+
1137+ // Signal watchdog to exit and wait for it
1138+ watchdog_cancel. store ( true , Ordering :: Relaxed ) ;
1139+ let _ = watchdog. join ( ) ;
11141140 trace ! (
11151141 "[THREAD-{}] Iteration {}: Guest call returned: {:?}" ,
11161142 thread_id,
0 commit comments