1
+ use std:: sync:: atomic:: AtomicU64 ;
2
+ use std:: sync:: Arc ;
1
3
use std:: time:: { Duration , Instant , SystemTime } ;
2
4
5
+ use rustc_data_structures:: sync:: Ordering ;
6
+
3
7
use crate :: concurrency:: thread:: Time ;
4
8
use crate :: * ;
5
9
10
+ #[ derive( Debug ) ]
11
+ pub enum TimeAnchor {
12
+ Host ( Instant ) ,
13
+ Virtual ( Arc < AtomicU64 > ) ,
14
+ }
15
+
16
+ impl TimeAnchor {
17
+ pub fn new ( communicate : bool ) -> Self {
18
+ if communicate { Self :: Host ( Instant :: now ( ) ) } else { Self :: Virtual ( Arc :: new ( 0 . into ( ) ) ) }
19
+ }
20
+
21
+ pub fn get ( & self ) -> Duration {
22
+ match self {
23
+ Self :: Host ( instant) => Instant :: now ( ) . saturating_duration_since ( * instant) ,
24
+ Self :: Virtual ( nanoseconds) => Duration :: from_nanos ( nanoseconds. load ( Ordering :: Relaxed ) ) ,
25
+ }
26
+ }
27
+
28
+ pub fn tick ( & self ) {
29
+ match self {
30
+ Self :: Host ( _) => ( ) ,
31
+ Self :: Virtual ( nanoseconds) => {
32
+ nanoseconds. fetch_add ( 1 , Ordering :: Relaxed ) ;
33
+ }
34
+ }
35
+ }
36
+
37
+ pub fn sleep ( & self , duration : Duration ) {
38
+ match self {
39
+ Self :: Host ( _) => std:: thread:: sleep ( duration) ,
40
+ Self :: Virtual ( nanoseconds) => {
41
+ nanoseconds. fetch_add ( duration. as_nanos ( ) . try_into ( ) . unwrap ( ) , Ordering :: Relaxed ) ;
42
+ }
43
+ }
44
+ }
45
+
46
+ pub fn checked_add_since_now ( & self , duration : Duration ) -> Option < Time > {
47
+ match self {
48
+ Self :: Host ( _) => Instant :: now ( ) . checked_add ( duration) . map ( Time :: Monotonic ) ,
49
+ Self :: Virtual ( nanoseconds) =>
50
+ nanoseconds
51
+ . load ( Ordering :: Relaxed )
52
+ . checked_add ( duration. as_nanos ( ) . try_into ( ) . unwrap ( ) )
53
+ . map ( |duration| Time :: Virtual ( duration, nanoseconds. clone ( ) ) ) ,
54
+ }
55
+ }
56
+
57
+ pub fn checked_add_since_start ( & self , duration : Duration ) -> Option < Time > {
58
+ match self {
59
+ Self :: Host ( instant) => instant. checked_add ( duration) . map ( Time :: Monotonic ) ,
60
+ Self :: Virtual ( now) =>
61
+ Some ( Time :: Virtual ( duration. as_nanos ( ) . try_into ( ) . unwrap ( ) , now. clone ( ) ) ) ,
62
+ }
63
+ }
64
+ }
65
+
6
66
/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
7
67
pub fn system_time_to_duration < ' tcx > ( time : & SystemTime ) -> InterpResult < ' tcx , Duration > {
8
68
time. duration_since ( SystemTime :: UNIX_EPOCH )
@@ -23,7 +83,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
23
83
let this = self . eval_context_mut ( ) ;
24
84
25
85
this. assert_target_os ( "linux" , "clock_gettime" ) ;
26
- this. check_no_isolation ( "`clock_gettime`" ) ?;
27
86
28
87
let clk_id = this. read_scalar ( clk_id_op) ?. to_i32 ( ) ?;
29
88
@@ -40,9 +99,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
40
99
[ this. eval_libc_i32 ( "CLOCK_MONOTONIC" ) ?, this. eval_libc_i32 ( "CLOCK_MONOTONIC_COARSE" ) ?] ;
41
100
42
101
let duration = if absolute_clocks. contains ( & clk_id) {
102
+ this. check_no_isolation ( "`clock_gettime` with real time clocks" ) ?;
43
103
system_time_to_duration ( & SystemTime :: now ( ) ) ?
44
104
} else if relative_clocks. contains ( & clk_id) {
45
- Instant :: now ( ) . duration_since ( this. machine . time_anchor )
105
+ this. machine . threads . time_anchor . get ( )
46
106
} else {
47
107
let einval = this. eval_libc ( "EINVAL" ) ?;
48
108
this. set_last_error ( einval) ?;
@@ -127,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
127
187
128
188
// QueryPerformanceCounter uses a hardware counter as its basis.
129
189
// Miri will emulate a counter with a resolution of 1 nanosecond.
130
- let duration = Instant :: now ( ) . duration_since ( this. machine . time_anchor ) ;
190
+ let duration = this. machine . threads . time_anchor . get ( ) ;
131
191
let qpc = i64:: try_from ( duration. as_nanos ( ) ) . map_err ( |_| {
132
192
err_unsup_format ! ( "programs running longer than 2^63 nanoseconds are not supported" )
133
193
} ) ?;
@@ -168,7 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
168
228
169
229
// This returns a u64, with time units determined dynamically by `mach_timebase_info`.
170
230
// We return plain nanoseconds.
171
- let duration = Instant :: now ( ) . duration_since ( this. machine . time_anchor ) ;
231
+ let duration = this. machine . threads . time_anchor . get ( ) ;
172
232
let res = u64:: try_from ( duration. as_nanos ( ) ) . map_err ( |_| {
173
233
err_unsup_format ! ( "programs running longer than 2^64 nanoseconds are not supported" )
174
234
} ) ?;
@@ -202,7 +262,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
202
262
let this = self . eval_context_mut ( ) ;
203
263
204
264
this. assert_target_os_is_unix ( "nanosleep" ) ;
205
- this. check_no_isolation ( "`nanosleep`" ) ?;
206
265
207
266
let duration = match this. read_timespec ( & this. deref_operand ( req_op) ?) ? {
208
267
Some ( duration) => duration,
@@ -213,10 +272,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
213
272
}
214
273
} ;
215
274
// If adding the duration overflows, let's just sleep for an hour. Waking up early is always acceptable.
216
- let timeout_time = Instant :: now ( )
217
- . checked_add ( duration)
218
- . unwrap_or_else ( || Instant :: now ( ) . checked_add ( Duration :: from_secs ( 3600 ) ) . unwrap ( ) ) ;
219
- let timeout_time = Time :: Monotonic ( timeout_time) ;
275
+ let timeout_time =
276
+ this. machine . threads . time_anchor . checked_add_since_now ( duration) . unwrap_or_else ( || {
277
+ this. machine
278
+ . threads
279
+ . time_anchor
280
+ . checked_add_since_now ( Duration :: from_secs ( 3600 ) )
281
+ . unwrap ( )
282
+ } ) ;
220
283
221
284
let active_thread = this. get_active_thread ( ) ;
222
285
this. block_thread ( active_thread) ;
@@ -238,12 +301,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
238
301
let this = self . eval_context_mut ( ) ;
239
302
240
303
this. assert_target_os ( "windows" , "Sleep" ) ;
241
- this. check_no_isolation ( "`Sleep`" ) ?;
242
304
243
305
let timeout_ms = this. read_scalar ( timeout) ?. to_u32 ( ) ?;
244
306
245
307
let duration = Duration :: from_millis ( timeout_ms. into ( ) ) ;
246
- let timeout_time = Time :: Monotonic ( Instant :: now ( ) . checked_add ( duration) . unwrap ( ) ) ;
308
+ let timeout_time =
309
+ this. machine . threads . time_anchor . checked_add_since_now ( duration) . unwrap ( ) ;
247
310
248
311
let active_thread = this. get_active_thread ( ) ;
249
312
this. block_thread ( active_thread) ;
0 commit comments