3
3
use std:: cell:: RefCell ;
4
4
use std:: collections:: hash_map:: Entry ;
5
5
use std:: num:: TryFromIntError ;
6
- use std:: sync:: atomic:: AtomicU64 ;
7
- use std:: sync:: Arc ;
8
6
use std:: time:: { Duration , Instant , SystemTime } ;
9
7
10
8
use log:: trace;
@@ -19,7 +17,7 @@ use rustc_target::spec::abi::Abi;
19
17
20
18
use crate :: concurrency:: data_race;
21
19
use crate :: concurrency:: sync:: SynchronizationState ;
22
- use crate :: shims:: time:: TimeAnchor ;
20
+ use crate :: shims:: time:: Clock ;
23
21
use crate :: * ;
24
22
25
23
#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
@@ -188,22 +186,17 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
188
186
#[ derive( Debug ) ]
189
187
pub enum Time {
190
188
Monotonic ( Instant ) ,
191
- Virtual {
192
- /// The instant for this moment.
193
- instant : u64 ,
194
- /// A reference to the time anchor used to read the current global virtual time.
195
- time_anchor : Arc < AtomicU64 > ,
196
- } ,
189
+ Virtual { nanoseconds : u64 } ,
197
190
RealTime ( SystemTime ) ,
198
191
}
199
192
200
193
impl Time {
201
194
/// How long do we have to wait from now until the specified time?
202
- fn get_wait_time ( & self ) -> Duration {
195
+ fn get_wait_time ( & self , clock : & Clock ) -> Duration {
203
196
match self {
204
197
Time :: Monotonic ( instant) => instant. saturating_duration_since ( Instant :: now ( ) ) ,
205
- Time :: Virtual { instant , time_anchor } =>
206
- Duration :: from_nanos ( instant - time_anchor . load ( Ordering :: Relaxed ) ) ,
198
+ Time :: Virtual { nanoseconds } =>
199
+ Duration :: from_nanos ( nanoseconds - clock . assert_virtual ( ) . load ( Ordering :: Relaxed ) ) ,
207
200
Time :: RealTime ( time) =>
208
201
time. duration_since ( SystemTime :: now ( ) ) . unwrap_or ( Duration :: new ( 0 , 0 ) ) ,
209
202
}
@@ -246,8 +239,6 @@ pub struct ThreadManager<'mir, 'tcx> {
246
239
yield_active_thread : bool ,
247
240
/// Callbacks that are called once the specified time passes.
248
241
timeout_callbacks : FxHashMap < ThreadId , TimeoutCallbackInfo < ' mir , ' tcx > > ,
249
- /// The "time anchor" for this machine's monotone clock (for `Instant` simulation).
250
- pub ( crate ) time_anchor : TimeAnchor ,
251
242
}
252
243
253
244
impl < ' mir , ' tcx > Default for ThreadManager < ' mir , ' tcx > {
@@ -262,7 +253,6 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
262
253
thread_local_alloc_ids : Default :: default ( ) ,
263
254
yield_active_thread : false ,
264
255
timeout_callbacks : FxHashMap :: default ( ) ,
265
- time_anchor : TimeAnchor :: new ( false ) ,
266
256
}
267
257
}
268
258
}
@@ -273,8 +263,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
273
263
// The main thread can *not* be joined on except on windows.
274
264
ecx. machine . threads . threads [ ThreadId :: new ( 0 ) ] . join_status = ThreadJoinStatus :: Detached ;
275
265
}
276
-
277
- ecx. machine . threads . time_anchor = TimeAnchor :: new ( ecx. machine . communicate ( ) ) ;
278
266
}
279
267
280
268
/// Check if we have an allocation for the given thread local static for the
@@ -503,13 +491,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
503
491
}
504
492
505
493
/// Get a callback that is ready to be called.
506
- fn get_ready_callback ( & mut self ) -> Option < ( ThreadId , TimeoutCallback < ' mir , ' tcx > ) > {
494
+ fn get_ready_callback (
495
+ & mut self ,
496
+ clock : & Clock ,
497
+ ) -> Option < ( ThreadId , TimeoutCallback < ' mir , ' tcx > ) > {
507
498
// We iterate over all threads in the order of their indices because
508
499
// this allows us to have a deterministic scheduler.
509
500
for thread in self . threads . indices ( ) {
510
501
match self . timeout_callbacks . entry ( thread) {
511
502
Entry :: Occupied ( entry) =>
512
- if entry. get ( ) . call_time . get_wait_time ( ) == Duration :: new ( 0 , 0 ) {
503
+ if entry. get ( ) . call_time . get_wait_time ( clock ) == Duration :: new ( 0 , 0 ) {
513
504
return Some ( ( thread, entry. remove ( ) . callback ) ) ;
514
505
} ,
515
506
Entry :: Vacant ( _) => { }
@@ -566,7 +557,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
566
557
/// used in stateless model checkers such as Loom: run the active thread as
567
558
/// long as we can and switch only when we have to (the active thread was
568
559
/// blocked, terminated, or has explicitly asked to be preempted).
569
- fn schedule ( & mut self ) -> InterpResult < ' tcx , SchedulingAction > {
560
+ fn schedule ( & mut self , clock : & Clock ) -> InterpResult < ' tcx , SchedulingAction > {
570
561
// Check whether the thread has **just** terminated (`check_terminated`
571
562
// checks whether the thread has popped all its stack and if yes, sets
572
563
// the thread state to terminated).
@@ -593,7 +584,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
593
584
// at the time of the call".
594
585
// <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html>
595
586
let potential_sleep_time =
596
- self . timeout_callbacks . values ( ) . map ( |info| info. call_time . get_wait_time ( ) ) . min ( ) ;
587
+ self . timeout_callbacks . values ( ) . map ( |info| info. call_time . get_wait_time ( clock ) ) . min ( ) ;
597
588
if potential_sleep_time == Some ( Duration :: new ( 0 , 0 ) ) {
598
589
return Ok ( SchedulingAction :: ExecuteTimeoutCallback ) ;
599
590
}
@@ -629,7 +620,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
629
620
// timeout_callbacks, which may unblock some of the threads. Hence,
630
621
// sleep until the first callback.
631
622
632
- self . time_anchor . sleep ( sleep_time) ;
623
+ clock . sleep ( sleep_time) ;
633
624
Ok ( SchedulingAction :: ExecuteTimeoutCallback )
634
625
} else {
635
626
throw_machine_stop ! ( TerminationInfo :: Deadlock ) ;
@@ -892,18 +883,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
892
883
#[ inline]
893
884
fn run_timeout_callback ( & mut self ) -> InterpResult < ' tcx > {
894
885
let this = self . eval_context_mut ( ) ;
895
- let ( thread, callback) =
896
- if let Some ( ( thread, callback) ) = this. machine . threads . get_ready_callback ( ) {
897
- ( thread, callback)
898
- } else {
899
- // get_ready_callback can return None if the computer's clock
900
- // was shifted after calling the scheduler and before the call
901
- // to get_ready_callback (see issue
902
- // https://github.com/rust-lang/miri/issues/1763). In this case,
903
- // just do nothing, which effectively just returns to the
904
- // scheduler.
905
- return Ok ( ( ) ) ;
906
- } ;
886
+ let ( thread, callback) = if let Some ( ( thread, callback) ) =
887
+ this. machine . threads . get_ready_callback ( & this. machine . clock )
888
+ {
889
+ ( thread, callback)
890
+ } else {
891
+ // get_ready_callback can return None if the computer's clock
892
+ // was shifted after calling the scheduler and before the call
893
+ // to get_ready_callback (see issue
894
+ // https://github.com/rust-lang/miri/issues/1763). In this case,
895
+ // just do nothing, which effectively just returns to the
896
+ // scheduler.
897
+ return Ok ( ( ) ) ;
898
+ } ;
907
899
// This back-and-forth with `set_active_thread` is here because of two
908
900
// design decisions:
909
901
// 1. Make the caller and not the callback responsible for changing
@@ -920,7 +912,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
920
912
#[ inline]
921
913
fn schedule ( & mut self ) -> InterpResult < ' tcx , SchedulingAction > {
922
914
let this = self . eval_context_mut ( ) ;
923
- this. machine . threads . schedule ( )
915
+ this. machine . threads . schedule ( & this . machine . clock )
924
916
}
925
917
926
918
/// Handles thread termination of the active thread: wakes up threads joining on this one,
0 commit comments