@@ -4,7 +4,7 @@ use std::cell::RefCell;
44use std:: collections:: hash_map:: Entry ;
55use std:: convert:: TryFrom ;
66use std:: num:: TryFromIntError ;
7- use std:: time:: Instant ;
7+ use std:: time:: { Duration , Instant , SystemTime } ;
88
99use log:: trace;
1010
@@ -159,13 +159,30 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
159159 }
160160}
161161
162+ #[ derive( Debug ) ]
163+ pub enum Time {
164+ Monotonic ( Instant ) ,
165+ RealTime ( SystemTime ) ,
166+ }
167+
168+ impl Time {
169+ /// How long do we have to wait from now until the specified time?
170+ fn get_wait_time ( & self ) -> Duration {
171+ match self {
172+ Time :: Monotonic ( instant) => instant. saturating_duration_since ( Instant :: now ( ) ) ,
173+ Time :: RealTime ( time) =>
174+ time. duration_since ( SystemTime :: now ( ) ) . unwrap_or ( Duration :: new ( 0 , 0 ) ) ,
175+ }
176+ }
177+ }
178+
162179/// Callbacks are used to implement timeouts. For example, waiting on a
163180/// conditional variable with a timeout creates a callback that is called after
164181/// the specified time and unblocks the thread. If another thread signals on the
165182/// conditional variable, the signal handler deletes the callback.
166183struct TimeoutCallbackInfo < ' mir , ' tcx > {
167184 /// The callback should be called no earlier than this time.
168- call_time : Instant ,
185+ call_time : Time ,
169186 /// The called function.
170187 callback : TimeoutCallback < ' mir , ' tcx > ,
171188}
@@ -362,11 +379,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
362379 fn register_timeout_callback (
363380 & mut self ,
364381 thread : ThreadId ,
365- call_time : Instant ,
382+ call_time : Time ,
366383 callback : TimeoutCallback < ' mir , ' tcx > ,
367384 ) {
368385 self . timeout_callbacks
369- . insert ( thread, TimeoutCallbackInfo { call_time : call_time , callback : callback } )
386+ . insert ( thread, TimeoutCallbackInfo { call_time, callback } )
370387 . unwrap_none ( ) ;
371388 }
372389
@@ -376,13 +393,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
376393 }
377394
378395 /// Get a callback that is ready to be called.
379- fn get_callback ( & mut self ) -> Option < ( ThreadId , TimeoutCallback < ' mir , ' tcx > ) > {
380- let current_time = Instant :: now ( ) ;
396+ fn get_ready_callback ( & mut self ) -> Option < ( ThreadId , TimeoutCallback < ' mir , ' tcx > ) > {
381397 // We use a for loop here to make the scheduler more deterministic.
382398 for thread in self . threads . indices ( ) {
383399 match self . timeout_callbacks . entry ( thread) {
384400 Entry :: Occupied ( entry) =>
385- if current_time >= entry. get ( ) . call_time {
401+ if entry. get ( ) . call_time . get_wait_time ( ) == Duration :: new ( 0 , 0 ) {
386402 return Some ( ( thread, entry. remove ( ) . callback ) ) ;
387403 } ,
388404 Entry :: Vacant ( _) => { }
@@ -445,18 +461,14 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
445461 }
446462 // We have not found a thread to execute.
447463 if self . threads . iter ( ) . all ( |thread| thread. state == ThreadState :: Terminated ) {
448- unreachable ! ( ) ;
449- } else if let Some ( next_call_time ) =
450- self . timeout_callbacks . values ( ) . min_by_key ( |info| info. call_time )
464+ unreachable ! ( "all threads terminated without the main thread terminating?!" ) ;
465+ } else if let Some ( sleep_time ) =
466+ self . timeout_callbacks . values ( ) . map ( |info| info. call_time . get_wait_time ( ) ) . min ( )
451467 {
452468 // All threads are currently blocked, but we have unexecuted
453469 // timeout_callbacks, which may unblock some of the threads. Hence,
454470 // sleep until the first callback.
455- if let Some ( sleep_time) =
456- next_call_time. call_time . checked_duration_since ( Instant :: now ( ) )
457- {
458- std:: thread:: sleep ( sleep_time) ;
459- }
471+ std:: thread:: sleep ( sleep_time) ;
460472 Ok ( SchedulingAction :: ExecuteTimeoutCallback )
461473 } else {
462474 throw_machine_stop ! ( TerminationInfo :: Deadlock ) ;
@@ -650,7 +662,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
650662 fn register_timeout_callback (
651663 & mut self ,
652664 thread : ThreadId ,
653- call_time : Instant ,
665+ call_time : Time ,
654666 callback : TimeoutCallback < ' mir , ' tcx > ,
655667 ) -> InterpResult < ' tcx > {
656668 let this = self . eval_context_mut ( ) ;
@@ -669,7 +681,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
669681 #[ inline]
670682 fn run_timeout_callback ( & mut self ) -> InterpResult < ' tcx > {
671683 let this = self . eval_context_mut ( ) ;
672- let ( thread, callback) = this. machine . threads . get_callback ( ) . expect ( "no callback found" ) ;
684+ let ( thread, callback) =
685+ this. machine . threads . get_ready_callback ( ) . expect ( "no callback found" ) ;
673686 let old_thread = this. set_active_thread ( thread) ?;
674687 callback ( this) ?;
675688 this. set_active_thread ( old_thread) ?;
0 commit comments