11//@ignore-target: windows # no libc time APIs on Windows
22//@compile-flags: -Zmiri-disable-isolation
3+ use std:: time:: { Duration , Instant } ;
34use std:: { env, mem, ptr} ;
45
56fn main ( ) {
@@ -20,6 +21,19 @@ fn main() {
2021 test_localtime_r_future_32b ( ) ;
2122 #[ cfg( target_pointer_width = "64" ) ]
2223 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+ }
2337}
2438
2539/// Tests whether clock support exists at all
@@ -315,3 +329,103 @@ fn test_localtime_r_multiple_calls_deduplication() {
315329 NUM_CALLS - 1
316330 ) ;
317331}
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