@@ -44,6 +44,7 @@ pub(super) struct DispatcherContext<'a, F> {
4444 stopwatch : StopwatchStart ,
4545 run_stats : RunStats ,
4646 max_fail : MaxFail ,
47+ global_timeout : Duration ,
4748 running_setup_script : Option < ContextSetupScript < ' a > > ,
4849 running_tests : BTreeMap < TestInstanceId < ' a > , ContextTestInstance < ' a > > ,
4950 cancel_state : Option < CancelReason > ,
6364 cli_args : Vec < String > ,
6465 initial_run_count : usize ,
6566 max_fail : MaxFail ,
67+ global_timeout : Duration ,
6668 ) -> Self {
6769 Self {
6870 callback : DebugIgnore ( callback) ,
7577 ..RunStats :: default ( )
7678 } ,
7779 max_fail,
80+ global_timeout,
7881 running_setup_script : None ,
7982 running_tests : BTreeMap :: new ( ) ,
8083 cancel_state : None ,
@@ -103,9 +106,14 @@ where
103106 let mut signals_done = false ;
104107 let mut inputs_done = false ;
105108 let mut report_cancel_rx_done = false ;
109+ let mut global_timeout_sleep =
110+ std:: pin:: pin!( crate :: time:: pausable_sleep( self . global_timeout) ) ;
106111
107112 loop {
108113 let internal_event = tokio:: select! {
114+ _ = & mut global_timeout_sleep => {
115+ InternalEvent :: GlobalTimeout
116+ } ,
109117 internal_event = executor_rx. recv( ) => {
110118 match internal_event {
111119 Some ( event) => InternalEvent :: Executor ( event) ,
@@ -201,13 +209,20 @@ where
201209 // Restore the terminal state.
202210 input_handler. suspend ( ) ;
203211
212+ // Pause the global timeout while suspended.
213+ global_timeout_sleep. as_mut ( ) . pause ( ) ;
214+
204215 // Now stop nextest itself.
205216 super :: os:: raise_stop ( ) ;
206217 }
207218 #[ cfg( unix) ]
208219 HandleEventResponse :: JobControl ( JobControlEvent :: Continue ) => {
209220 // Nextest has been resumed. Resume the input handler, as well as all the tests.
210221 input_handler. resume ( ) ;
222+
223+ // Resume the global timeout.
224+ global_timeout_sleep. as_mut ( ) . resume ( ) ;
225+
211226 self . broadcast_request ( RunUnitRequest :: Signal ( SignalRequest :: Continue ) ) ;
212227 }
213228 #[ cfg( not( unix) ) ]
@@ -285,6 +300,10 @@ where
285300 // A test failure has caused cancellation to begin.
286301 self . broadcast_request ( RunUnitRequest :: OtherCancel ) ;
287302 }
303+ CancelEvent :: GlobalTimeout => {
304+ // The global timeout has expired, causing cancellation to begin.
305+ self . broadcast_request ( RunUnitRequest :: OtherCancel ) ;
306+ }
288307 CancelEvent :: Signal ( req) => {
289308 // A signal has caused cancellation to begin. Let all the child
290309 // processes know about the signal, and continue to handle
@@ -534,6 +553,9 @@ where
534553 } )
535554 }
536555 InternalEvent :: Signal ( event) => self . handle_signal_event ( event) ,
556+ InternalEvent :: GlobalTimeout => {
557+ self . begin_cancel ( CancelReason :: GlobalTimeout , CancelEvent :: GlobalTimeout )
558+ }
537559 InternalEvent :: Input ( InputEvent :: Info ) => {
538560 // Print current statistics.
539561 HandleEventResponse :: Info ( InfoEvent :: Input )
@@ -850,6 +872,7 @@ enum InternalEvent<'a> {
850872 Signal ( SignalEvent ) ,
851873 Input ( InputEvent ) ,
852874 ReportCancel ,
875+ GlobalTimeout ,
853876}
854877
855878/// The return result of `handle_event`.
@@ -883,6 +906,7 @@ enum InfoEvent {
883906enum CancelEvent {
884907 Report ,
885908 TestFailure ,
909+ GlobalTimeout ,
886910 Signal ( ShutdownRequest ) ,
887911}
888912
@@ -919,7 +943,9 @@ mod tests {
919943 vec ! [ ] ,
920944 0 ,
921945 MaxFail :: All ,
946+ crate :: time:: far_future_duration ( ) ,
922947 ) ;
948+
923949 cx. disable_signal_3_times_panic = true ;
924950
925951 // Begin cancellation with a report error.
0 commit comments