@@ -4,7 +4,7 @@ use std::cell::RefCell;
4
4
use std:: collections:: hash_map:: Entry ;
5
5
use std:: convert:: TryFrom ;
6
6
use std:: num:: TryFromIntError ;
7
- use std:: time:: Instant ;
7
+ use std:: time:: { Duration , Instant , SystemTime } ;
8
8
9
9
use log:: trace;
10
10
@@ -159,13 +159,30 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
159
159
}
160
160
}
161
161
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
+
162
179
/// Callbacks are used to implement timeouts. For example, waiting on a
163
180
/// conditional variable with a timeout creates a callback that is called after
164
181
/// the specified time and unblocks the thread. If another thread signals on the
165
182
/// conditional variable, the signal handler deletes the callback.
166
183
struct TimeoutCallbackInfo < ' mir , ' tcx > {
167
184
/// The callback should be called no earlier than this time.
168
- call_time : Instant ,
185
+ call_time : Time ,
169
186
/// The called function.
170
187
callback : TimeoutCallback < ' mir , ' tcx > ,
171
188
}
@@ -362,11 +379,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
362
379
fn register_timeout_callback (
363
380
& mut self ,
364
381
thread : ThreadId ,
365
- call_time : Instant ,
382
+ call_time : Time ,
366
383
callback : TimeoutCallback < ' mir , ' tcx > ,
367
384
) {
368
385
self . timeout_callbacks
369
- . insert ( thread, TimeoutCallbackInfo { call_time : call_time , callback : callback } )
386
+ . insert ( thread, TimeoutCallbackInfo { call_time, callback } )
370
387
. unwrap_none ( ) ;
371
388
}
372
389
@@ -376,13 +393,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
376
393
}
377
394
378
395
/// 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 > ) > {
381
397
// We use a for loop here to make the scheduler more deterministic.
382
398
for thread in self . threads . indices ( ) {
383
399
match self . timeout_callbacks . entry ( thread) {
384
400
Entry :: Occupied ( entry) =>
385
- if current_time >= entry. get ( ) . call_time {
401
+ if entry. get ( ) . call_time . get_wait_time ( ) == Duration :: new ( 0 , 0 ) {
386
402
return Some ( ( thread, entry. remove ( ) . callback ) ) ;
387
403
} ,
388
404
Entry :: Vacant ( _) => { }
@@ -445,18 +461,14 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
445
461
}
446
462
// We have not found a thread to execute.
447
463
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 ( )
451
467
{
452
468
// All threads are currently blocked, but we have unexecuted
453
469
// timeout_callbacks, which may unblock some of the threads. Hence,
454
470
// 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) ;
460
472
Ok ( SchedulingAction :: ExecuteTimeoutCallback )
461
473
} else {
462
474
throw_machine_stop ! ( TerminationInfo :: Deadlock ) ;
@@ -650,7 +662,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
650
662
fn register_timeout_callback (
651
663
& mut self ,
652
664
thread : ThreadId ,
653
- call_time : Instant ,
665
+ call_time : Time ,
654
666
callback : TimeoutCallback < ' mir , ' tcx > ,
655
667
) -> InterpResult < ' tcx > {
656
668
let this = self . eval_context_mut ( ) ;
@@ -669,7 +681,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
669
681
#[ inline]
670
682
fn run_timeout_callback ( & mut self ) -> InterpResult < ' tcx > {
671
683
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" ) ;
673
686
let old_thread = this. set_active_thread ( thread) ?;
674
687
callback ( this) ?;
675
688
this. set_active_thread ( old_thread) ?;
0 commit comments