|
1 | 1 | // ignore-windows: No libc on Windows |
| 2 | +// ignore-macos: pthread_condattr_setclock is not supported on MacOS. |
2 | 3 | // compile-flags: -Zmiri-disable-isolation |
3 | 4 |
|
4 | 5 | #![feature(rustc_private)] |
5 | 6 |
|
| 7 | +/// Test that conditional variable timeouts are working properly with both |
| 8 | +/// monotonic and system clocks. |
6 | 9 | extern crate libc; |
7 | 10 |
|
8 | | -use std::cell::UnsafeCell; |
9 | | -use std::mem::{self, MaybeUninit}; |
10 | | -use std::sync::Arc; |
11 | | -use std::thread; |
| 11 | +use std::mem; |
| 12 | +use std::time::Instant; |
12 | 13 |
|
13 | | -struct Mutex { |
14 | | - inner: UnsafeCell<libc::pthread_mutex_t>, |
15 | | -} |
16 | | - |
17 | | -unsafe impl Sync for Mutex {} |
18 | | - |
19 | | -impl std::fmt::Debug for Mutex { |
20 | | - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
21 | | - write!(f, "Mutex") |
22 | | - } |
23 | | -} |
24 | | - |
25 | | -struct Cond { |
26 | | - inner: UnsafeCell<libc::pthread_cond_t>, |
27 | | -} |
28 | | - |
29 | | -unsafe impl Sync for Cond {} |
30 | | - |
31 | | -impl std::fmt::Debug for Cond { |
32 | | - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
33 | | - write!(f, "Cond") |
34 | | - } |
35 | | -} |
36 | | - |
37 | | -unsafe fn create_cond_attr_monotonic() -> libc::pthread_condattr_t { |
38 | | - let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit(); |
39 | | - assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0); |
40 | | - assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC), 0); |
41 | | - attr.assume_init() |
42 | | -} |
43 | | - |
44 | | -unsafe fn create_cond(attr: Option<libc::pthread_condattr_t>) -> Cond { |
45 | | - let cond: Cond = mem::zeroed(); |
46 | | - if let Some(mut attr) = attr { |
47 | | - assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, &attr as *const _), 0); |
48 | | - assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); |
49 | | - } else { |
50 | | - assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, 0 as *const _), 0); |
51 | | - } |
52 | | - cond |
53 | | -} |
54 | | - |
55 | | -unsafe fn create_mutex() -> Mutex { |
56 | | - mem::zeroed() |
57 | | -} |
58 | | - |
59 | | -unsafe fn create_timeout(seconds: i64) -> libc::timespec { |
60 | | - let mut now: libc::timespec = mem::zeroed(); |
61 | | - assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0); |
62 | | - libc::timespec { tv_sec: now.tv_sec + seconds, tv_nsec: now.tv_nsec } |
63 | | -} |
64 | | - |
65 | | -fn test_pthread_condattr_t() { |
| 14 | +fn test_timed_wait_timeout_monotonic() { |
66 | 15 | unsafe { |
67 | | - let mut attr = create_cond_attr_monotonic(); |
68 | | - let mut clock_id = MaybeUninit::<libc::clockid_t>::uninit(); |
69 | | - assert_eq!(libc::pthread_condattr_getclock(&attr as *const _, clock_id.as_mut_ptr()), 0); |
70 | | - assert_eq!(clock_id.assume_init(), libc::CLOCK_MONOTONIC); |
71 | | - assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); |
72 | | - } |
73 | | -} |
| 16 | + let mut attr: libc::pthread_condattr_t = mem::zeroed(); |
| 17 | + assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); |
| 18 | + assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_MONOTONIC), 0); |
74 | 19 |
|
75 | | -fn test_signal() { |
76 | | - unsafe { |
77 | | - let cond = Arc::new(create_cond(None)); |
78 | | - let mutex = Arc::new(create_mutex()); |
| 20 | + let mut cond: libc::pthread_cond_t = mem::zeroed(); |
| 21 | + assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); |
| 22 | + assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); |
79 | 23 |
|
80 | | - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); |
| 24 | + let mut mutex: libc::pthread_mutex_t = mem::zeroed(); |
81 | 25 |
|
82 | | - let spawn_mutex = Arc::clone(&mutex); |
83 | | - let spawn_cond = Arc::clone(&cond); |
84 | | - let handle = thread::spawn(move || { |
85 | | - assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); |
86 | | - assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0); |
87 | | - assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); |
88 | | - }); |
| 26 | + let mut now: libc::timespec = mem::zeroed(); |
| 27 | + assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0); |
| 28 | + let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; |
89 | 29 |
|
| 30 | + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); |
| 31 | + let current_time = Instant::now(); |
90 | 32 | assert_eq!( |
91 | | - libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _), |
92 | | - 0 |
| 33 | + libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), |
| 34 | + libc::ETIMEDOUT |
93 | 35 | ); |
94 | | - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); |
95 | | - |
96 | | - handle.join().unwrap(); |
97 | | - |
98 | | - let mutex = Arc::try_unwrap(mutex).unwrap(); |
99 | | - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); |
100 | | - let cond = Arc::try_unwrap(cond).unwrap(); |
101 | | - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); |
| 36 | + assert!(current_time.elapsed().as_millis() >= 900); |
| 37 | + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); |
| 38 | + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); |
| 39 | + assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); |
102 | 40 | } |
103 | 41 | } |
104 | 42 |
|
105 | | -fn test_broadcast() { |
| 43 | +fn test_timed_wait_timeout_realtime() { |
106 | 44 | unsafe { |
107 | | - let cond = Arc::new(create_cond(None)); |
108 | | - let mutex = Arc::new(create_mutex()); |
109 | | - |
110 | | - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); |
111 | | - |
112 | | - let spawn_mutex = Arc::clone(&mutex); |
113 | | - let spawn_cond = Arc::clone(&cond); |
114 | | - let handle = thread::spawn(move || { |
115 | | - assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); |
116 | | - assert_eq!(libc::pthread_cond_broadcast(spawn_cond.inner.get() as *mut _), 0); |
117 | | - assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); |
118 | | - }); |
| 45 | + let mut attr: libc::pthread_condattr_t = mem::zeroed(); |
| 46 | + assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); |
| 47 | + assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_REALTIME), 0); |
119 | 48 |
|
120 | | - assert_eq!( |
121 | | - libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _), |
122 | | - 0 |
123 | | - ); |
124 | | - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); |
| 49 | + let mut cond: libc::pthread_cond_t = mem::zeroed(); |
| 50 | + assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); |
| 51 | + assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); |
125 | 52 |
|
126 | | - handle.join().unwrap(); |
| 53 | + let mut mutex: libc::pthread_mutex_t = mem::zeroed(); |
127 | 54 |
|
128 | | - let mutex = Arc::try_unwrap(mutex).unwrap(); |
129 | | - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); |
130 | | - let cond = Arc::try_unwrap(cond).unwrap(); |
131 | | - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); |
132 | | - } |
133 | | -} |
| 55 | + let mut now: libc::timespec = mem::zeroed(); |
| 56 | + assert_eq!(libc::clock_gettime(libc::CLOCK_REALTIME, &mut now), 0); |
| 57 | + let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; |
134 | 58 |
|
135 | | -fn test_timed_wait_timeout() { |
136 | | - unsafe { |
137 | | - let attr = create_cond_attr_monotonic(); |
138 | | - let cond = create_cond(Some(attr)); |
139 | | - let mutex = create_mutex(); |
140 | | - let timeout = create_timeout(1); |
141 | | - |
142 | | - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); |
| 59 | + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); |
| 60 | + let current_time = Instant::now(); |
143 | 61 | assert_eq!( |
144 | | - libc::pthread_cond_timedwait( |
145 | | - cond.inner.get() as *mut _, |
146 | | - mutex.inner.get() as *mut _, |
147 | | - &timeout |
148 | | - ), |
| 62 | + libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), |
149 | 63 | libc::ETIMEDOUT |
150 | 64 | ); |
151 | | - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); |
152 | | - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); |
153 | | - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); |
154 | | - } |
155 | | -} |
156 | | - |
157 | | -fn test_timed_wait_notimeout() { |
158 | | - unsafe { |
159 | | - let attr = create_cond_attr_monotonic(); |
160 | | - let cond = Arc::new(create_cond(Some(attr))); |
161 | | - let mutex = Arc::new(create_mutex()); |
162 | | - let timeout = create_timeout(100); |
163 | | - |
164 | | - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); |
165 | | - |
166 | | - let spawn_mutex = Arc::clone(&mutex); |
167 | | - let spawn_cond = Arc::clone(&cond); |
168 | | - let handle = thread::spawn(move || { |
169 | | - assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); |
170 | | - assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0); |
171 | | - assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); |
172 | | - }); |
173 | | - |
174 | | - assert_eq!( |
175 | | - libc::pthread_cond_timedwait( |
176 | | - cond.inner.get() as *mut _, |
177 | | - mutex.inner.get() as *mut _, |
178 | | - &timeout |
179 | | - ), |
180 | | - 0 |
181 | | - ); |
182 | | - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); |
183 | | - |
184 | | - handle.join().unwrap(); |
185 | | - |
186 | | - let mutex = Arc::try_unwrap(mutex).unwrap(); |
187 | | - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); |
188 | | - let cond = Arc::try_unwrap(cond).unwrap(); |
189 | | - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); |
| 65 | + assert!(current_time.elapsed().as_millis() >= 900); |
| 66 | + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); |
| 67 | + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); |
| 68 | + assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); |
190 | 69 | } |
191 | 70 | } |
192 | 71 |
|
193 | 72 | fn main() { |
194 | | - test_pthread_condattr_t(); |
195 | | - test_signal(); |
196 | | - test_broadcast(); |
197 | | - test_timed_wait_timeout(); |
198 | | - test_timed_wait_notimeout(); |
| 73 | + test_timed_wait_timeout_monotonic(); |
| 74 | + test_timed_wait_timeout_realtime(); |
199 | 75 | } |
0 commit comments