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