33use std:: cell:: RefCell ;
44use std:: collections:: hash_map:: Entry ;
55use std:: num:: TryFromIntError ;
6- use std:: time:: { Duration , Instant , SystemTime } ;
6+ use std:: time:: { Duration , SystemTime } ;
77
88use log:: trace;
99
@@ -189,9 +189,9 @@ pub enum Time {
189189
190190impl Time {
191191 /// How long do we have to wait from now until the specified time?
192- fn get_wait_time ( & self ) -> Duration {
192+ fn get_wait_time ( & self , clock : & Clock ) -> Duration {
193193 match self {
194- Time :: Monotonic ( instant) => instant. saturating_duration_since ( Instant :: now ( ) ) ,
194+ Time :: Monotonic ( instant) => instant. duration_since ( clock . now ( ) ) ,
195195 Time :: RealTime ( time) =>
196196 time. duration_since ( SystemTime :: now ( ) ) . unwrap_or ( Duration :: new ( 0 , 0 ) ) ,
197197 }
@@ -490,13 +490,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
490490 }
491491
492492 /// Get a callback that is ready to be called.
493- fn get_ready_callback ( & mut self ) -> Option < ( ThreadId , TimeoutCallback < ' mir , ' tcx > ) > {
493+ fn get_ready_callback (
494+ & mut self ,
495+ clock : & Clock ,
496+ ) -> Option < ( ThreadId , TimeoutCallback < ' mir , ' tcx > ) > {
494497 // We iterate over all threads in the order of their indices because
495498 // this allows us to have a deterministic scheduler.
496499 for thread in self . threads . indices ( ) {
497500 match self . timeout_callbacks . entry ( thread) {
498501 Entry :: Occupied ( entry) =>
499- if entry. get ( ) . call_time . get_wait_time ( ) == Duration :: new ( 0 , 0 ) {
502+ if entry. get ( ) . call_time . get_wait_time ( clock ) == Duration :: new ( 0 , 0 ) {
500503 return Some ( ( thread, entry. remove ( ) . callback ) ) ;
501504 } ,
502505 Entry :: Vacant ( _) => { }
@@ -553,7 +556,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
553556 /// used in stateless model checkers such as Loom: run the active thread as
554557 /// long as we can and switch only when we have to (the active thread was
555558 /// blocked, terminated, or has explicitly asked to be preempted).
556- fn schedule ( & mut self ) -> InterpResult < ' tcx , SchedulingAction > {
559+ fn schedule ( & mut self , clock : & Clock ) -> InterpResult < ' tcx , SchedulingAction > {
557560 // Check whether the thread has **just** terminated (`check_terminated`
558561 // checks whether the thread has popped all its stack and if yes, sets
559562 // the thread state to terminated).
@@ -580,7 +583,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
580583 // at the time of the call".
581584 // <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html>
582585 let potential_sleep_time =
583- self . timeout_callbacks . values ( ) . map ( |info| info. call_time . get_wait_time ( ) ) . min ( ) ;
586+ self . timeout_callbacks . values ( ) . map ( |info| info. call_time . get_wait_time ( clock ) ) . min ( ) ;
584587 if potential_sleep_time == Some ( Duration :: new ( 0 , 0 ) ) {
585588 return Ok ( SchedulingAction :: ExecuteTimeoutCallback ) ;
586589 }
@@ -615,7 +618,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
615618 // All threads are currently blocked, but we have unexecuted
616619 // timeout_callbacks, which may unblock some of the threads. Hence,
617620 // sleep until the first callback.
618- std:: thread:: sleep ( sleep_time) ;
621+
622+ clock. sleep ( sleep_time) ;
619623 Ok ( SchedulingAction :: ExecuteTimeoutCallback )
620624 } else {
621625 throw_machine_stop ! ( TerminationInfo :: Deadlock ) ;
@@ -865,6 +869,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
865869 callback : TimeoutCallback < ' mir , ' tcx > ,
866870 ) {
867871 let this = self . eval_context_mut ( ) ;
872+ if !this. machine . communicate ( ) && matches ! ( call_time, Time :: RealTime ( ..) ) {
873+ panic ! ( "cannot have `RealTime` callback with isolation enabled!" )
874+ }
868875 this. machine . threads . register_timeout_callback ( thread, call_time, callback) ;
869876 }
870877
@@ -878,18 +885,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
878885 #[ inline]
879886 fn run_timeout_callback ( & mut self ) -> InterpResult < ' tcx > {
880887 let this = self . eval_context_mut ( ) ;
881- let ( thread, callback) =
882- if let Some ( ( thread, callback) ) = this. machine . threads . get_ready_callback ( ) {
883- ( thread, callback)
884- } else {
885- // get_ready_callback can return None if the computer's clock
886- // was shifted after calling the scheduler and before the call
887- // to get_ready_callback (see issue
888- // https://github.com/rust-lang/miri/issues/1763). In this case,
889- // just do nothing, which effectively just returns to the
890- // scheduler.
891- return Ok ( ( ) ) ;
892- } ;
888+ let ( thread, callback) = if let Some ( ( thread, callback) ) =
889+ this. machine . threads . get_ready_callback ( & this. machine . clock )
890+ {
891+ ( thread, callback)
892+ } else {
893+ // get_ready_callback can return None if the computer's clock
894+ // was shifted after calling the scheduler and before the call
895+ // to get_ready_callback (see issue
896+ // https://github.com/rust-lang/miri/issues/1763). In this case,
897+ // just do nothing, which effectively just returns to the
898+ // scheduler.
899+ return Ok ( ( ) ) ;
900+ } ;
893901 // This back-and-forth with `set_active_thread` is here because of two
894902 // design decisions:
895903 // 1. Make the caller and not the callback responsible for changing
@@ -906,7 +914,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
906914 #[ inline]
907915 fn schedule ( & mut self ) -> InterpResult < ' tcx , SchedulingAction > {
908916 let this = self . eval_context_mut ( ) ;
909- this. machine . threads . schedule ( )
917+ this. machine . threads . schedule ( & this . machine . clock )
910918 }
911919
912920 /// Handles thread termination of the active thread: wakes up threads joining on this one,
0 commit comments