|
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