]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_isolated.rs
Rollup merge of #104163 - H4x5:once-repeat-with-debug, r=dtolnay
[rust.git] / src / tools / miri / tests / pass-dep / concurrency / libc_pthread_cond_isolated.rs
1 //@ignore-target-windows: No libc on Windows
2 //@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS.
3
4 /// Test that conditional variable timeouts are working properly
5 /// with monotonic clocks even under isolation.
6 use std::mem::MaybeUninit;
7 use std::time::Instant;
8
9 fn test_timed_wait_timeout(clock_id: i32) {
10     unsafe {
11         let mut attr: MaybeUninit<libc::pthread_condattr_t> = MaybeUninit::uninit();
12         assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0);
13         assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), clock_id), 0);
14
15         let mut cond: MaybeUninit<libc::pthread_cond_t> = MaybeUninit::uninit();
16         assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), attr.as_ptr()), 0);
17         assert_eq!(libc::pthread_condattr_destroy(attr.as_mut_ptr()), 0);
18
19         let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
20
21         let mut now_mu: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
22         assert_eq!(libc::clock_gettime(clock_id, now_mu.as_mut_ptr()), 0);
23         let now = now_mu.assume_init();
24         // Waiting for a second... mostly because waiting less requires mich more tricky arithmetic.
25         // FIXME: wait less.
26         let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec };
27
28         assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
29         let current_time = Instant::now();
30         assert_eq!(
31             libc::pthread_cond_timedwait(cond.as_mut_ptr(), &mut mutex as *mut _, &timeout),
32             libc::ETIMEDOUT
33         );
34         let elapsed_time = current_time.elapsed().as_millis();
35         assert!(900 <= elapsed_time && elapsed_time <= 1300);
36
37         // Test calling `pthread_cond_timedwait` again with an already elapsed timeout.
38         assert_eq!(
39             libc::pthread_cond_timedwait(cond.as_mut_ptr(), &mut mutex as *mut _, &timeout),
40             libc::ETIMEDOUT
41         );
42
43         // Test that invalid nanosecond values (above 10^9 or negative) are rejected with the
44         // correct error code.
45         let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 };
46         assert_eq!(
47             libc::pthread_cond_timedwait(
48                 cond.as_mut_ptr(),
49                 &mut mutex as *mut _,
50                 &invalid_timeout_1
51             ),
52             libc::EINVAL
53         );
54         let invalid_timeout_2 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: -1 };
55         assert_eq!(
56             libc::pthread_cond_timedwait(
57                 cond.as_mut_ptr(),
58                 &mut mutex as *mut _,
59                 &invalid_timeout_2
60             ),
61             libc::EINVAL
62         );
63         // Test that invalid second values (negative) are rejected with the correct error code.
64         let invalid_timeout_3 = libc::timespec { tv_sec: -1, tv_nsec: 0 };
65         assert_eq!(
66             libc::pthread_cond_timedwait(
67                 cond.as_mut_ptr(),
68                 &mut mutex as *mut _,
69                 &invalid_timeout_3
70             ),
71             libc::EINVAL
72         );
73
74         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
75         assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
76         assert_eq!(libc::pthread_cond_destroy(cond.as_mut_ptr()), 0);
77     }
78 }
79
80 fn main() {
81     test_timed_wait_timeout(libc::CLOCK_MONOTONIC);
82 }