1
1
//@ignore-target: windows # no libc time APIs on Windows
2
2
//@compile-flags: -Zmiri-disable-isolation
3
+ use std:: time:: { Duration , Instant } ;
3
4
use std:: { env, mem, ptr} ;
4
5
5
6
fn main ( ) {
@@ -20,6 +21,19 @@ fn main() {
20
21
test_localtime_r_future_32b ( ) ;
21
22
#[ cfg( target_pointer_width = "64" ) ]
22
23
test_localtime_r_future_64b ( ) ;
24
+
25
+ test_nanosleep ( ) ;
26
+ #[ cfg( any(
27
+ target_os = "freebsd" ,
28
+ target_os = "linux" ,
29
+ target_os = "android" ,
30
+ target_os = "solaris" ,
31
+ target_os = "illumos"
32
+ ) ) ]
33
+ {
34
+ test_clock_nanosleep:: absolute ( ) ;
35
+ test_clock_nanosleep:: relative ( ) ;
36
+ }
23
37
}
24
38
25
39
/// Tests whether clock support exists at all
@@ -315,3 +329,103 @@ fn test_localtime_r_multiple_calls_deduplication() {
315
329
NUM_CALLS - 1
316
330
) ;
317
331
}
332
+
333
+ fn test_nanosleep ( ) {
334
+ let start_test_sleep = Instant :: now ( ) ;
335
+ let duration_zero = libc:: timespec { tv_sec : 0 , tv_nsec : 0 } ;
336
+ let remainder = ptr:: null_mut :: < libc:: timespec > ( ) ;
337
+ let is_error = unsafe { libc:: nanosleep ( & duration_zero, remainder) } ;
338
+ assert_eq ! ( is_error, 0 ) ;
339
+ assert ! ( start_test_sleep. elapsed( ) < Duration :: from_millis( 10 ) ) ;
340
+
341
+ let start_test_sleep = Instant :: now ( ) ;
342
+ let duration_100_millis = libc:: timespec { tv_sec : 0 , tv_nsec : 1_000_000_000 / 10 } ;
343
+ let remainder = ptr:: null_mut :: < libc:: timespec > ( ) ;
344
+ let is_error = unsafe { libc:: nanosleep ( & duration_100_millis, remainder) } ;
345
+ assert_eq ! ( is_error, 0 ) ;
346
+ assert ! ( start_test_sleep. elapsed( ) > Duration :: from_millis( 100 ) ) ;
347
+ }
348
+
349
+ #[ cfg( any(
350
+ target_os = "freebsd" ,
351
+ target_os = "linux" ,
352
+ target_os = "android" ,
353
+ target_os = "solaris" ,
354
+ target_os = "illumos"
355
+ ) ) ]
356
+ mod test_clock_nanosleep {
357
+ use super :: * ;
358
+
359
+ /// Helper function used to create an instant in the future
360
+ fn add_100_millis ( mut ts : libc:: timespec ) -> libc:: timespec {
361
+ // While tv_nsec has type `c_long` tv_sec has type `time_t`. These might
362
+ // end up as different types (for example: like i32 and i64).
363
+ const SECOND : libc:: c_long = 1_000_000_000 ;
364
+ ts. tv_nsec += SECOND / 10 ;
365
+ // If this pushes tv_nsec to SECOND or higher, we need to overflow to tv_sec.
366
+ ts. tv_sec += ( ts. tv_nsec / SECOND ) as libc:: time_t ;
367
+ ts. tv_nsec %= SECOND ;
368
+ ts
369
+ }
370
+
371
+ /// Helper function to get the current time for testing relative sleeps
372
+ fn timespec_now ( clock : libc:: clockid_t ) -> libc:: timespec {
373
+ let mut timespec = mem:: MaybeUninit :: < libc:: timespec > :: uninit ( ) ;
374
+ let is_error = unsafe { libc:: clock_gettime ( clock, timespec. as_mut_ptr ( ) ) } ;
375
+ assert_eq ! ( is_error, 0 ) ;
376
+ unsafe { timespec. assume_init ( ) }
377
+ }
378
+
379
+ pub fn absolute ( ) {
380
+ let start_test_sleep = Instant :: now ( ) ;
381
+ let before_start = libc:: timespec { tv_sec : 0 , tv_nsec : 0 } ;
382
+ let remainder = ptr:: null_mut :: < libc:: timespec > ( ) ;
383
+ let error = unsafe {
384
+ // this will not sleep since unix time zero is in the past
385
+ libc:: clock_nanosleep (
386
+ libc:: CLOCK_MONOTONIC ,
387
+ libc:: TIMER_ABSTIME ,
388
+ & before_start,
389
+ remainder,
390
+ )
391
+ } ;
392
+ assert_eq ! ( error, 0 ) ;
393
+ assert ! ( start_test_sleep. elapsed( ) < Duration :: from_millis( 10 ) ) ;
394
+
395
+ let start_test_sleep = Instant :: now ( ) ;
396
+ let hunderd_millis_after_start = add_100_millis ( timespec_now ( libc:: CLOCK_MONOTONIC ) ) ;
397
+ let remainder = ptr:: null_mut :: < libc:: timespec > ( ) ;
398
+ let error = unsafe {
399
+ libc:: clock_nanosleep (
400
+ libc:: CLOCK_MONOTONIC ,
401
+ libc:: TIMER_ABSTIME ,
402
+ & hunderd_millis_after_start,
403
+ remainder,
404
+ )
405
+ } ;
406
+ assert_eq ! ( error, 0 ) ;
407
+ assert ! ( start_test_sleep. elapsed( ) > Duration :: from_millis( 100 ) ) ;
408
+ }
409
+
410
+ pub fn relative ( ) {
411
+ const NO_FLAGS : i32 = 0 ;
412
+
413
+ let start_test_sleep = Instant :: now ( ) ;
414
+ let duration_zero = libc:: timespec { tv_sec : 0 , tv_nsec : 0 } ;
415
+ let remainder = ptr:: null_mut :: < libc:: timespec > ( ) ;
416
+ let error = unsafe {
417
+ libc:: clock_nanosleep ( libc:: CLOCK_MONOTONIC , NO_FLAGS , & duration_zero, remainder)
418
+ } ;
419
+ assert_eq ! ( error, 0 ) ;
420
+ assert ! ( start_test_sleep. elapsed( ) < Duration :: from_millis( 10 ) ) ;
421
+
422
+ let start_test_sleep = Instant :: now ( ) ;
423
+ let duration_100_millis = libc:: timespec { tv_sec : 0 , tv_nsec : 1_000_000_000 / 10 } ;
424
+ let remainder = ptr:: null_mut :: < libc:: timespec > ( ) ;
425
+ let error = unsafe {
426
+ libc:: clock_nanosleep ( libc:: CLOCK_MONOTONIC , NO_FLAGS , & duration_100_millis, remainder)
427
+ } ;
428
+ assert_eq ! ( error, 0 ) ;
429
+ assert ! ( start_test_sleep. elapsed( ) > Duration :: from_millis( 100 ) ) ;
430
+ }
431
+ }
0 commit comments