1 // ignore-windows: Concurrency on Windows is not supported yet.
2 // compile-flags: -Zmiri-disable-isolation
4 use std::sync::mpsc::{channel, sync_channel};
5 use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
7 use std::time::{Duration, Instant};
9 // Check if Rust barriers are working.
11 /// This test is taken from the Rust documentation.
13 let mut handles = Vec::with_capacity(10);
14 let barrier = Arc::new(Barrier::new(10));
16 let c = barrier.clone();
17 // The same messages will be printed together.
18 // You will NOT see any interleaving.
19 handles.push(thread::spawn(move || {
20 println!("before wait");
22 println!("after wait");
25 // Wait for other threads to finish.
26 for handle in handles {
27 handle.join().unwrap();
31 // Check if Rust conditional variables are working.
33 /// The test taken from the Rust documentation.
34 fn check_conditional_variables_notify_one() {
35 let pair = Arc::new((Mutex::new(false), Condvar::new()));
36 let pair2 = pair.clone();
38 // Spawn a new thread.
39 thread::spawn(move || {
41 let (lock, cvar) = &*pair2;
42 let mut started = lock.lock().unwrap();
44 // We notify the condvar that the value has changed.
48 // Wait for the thread to fully start up.
49 let (lock, cvar) = &*pair;
50 let mut started = lock.lock().unwrap();
52 started = cvar.wait(started).unwrap();
56 fn check_conditional_variables_notify_all() {
57 let pair = Arc::new(((Mutex::new(())), Condvar::new()));
59 // Spawn threads and block them on the conditional variable.
60 let handles: Vec<_> = (0..5)
62 let pair2 = pair.clone();
63 thread::spawn(move || {
64 let (lock, cvar) = &*pair2;
65 let guard = lock.lock().unwrap();
66 // Block waiting on the conditional variable.
67 let _ = cvar.wait(guard).unwrap();
76 let (_, cvar) = &*pair;
77 // Unblock all threads.
80 for handle in handles {
81 handle.join().unwrap();
85 /// Test that waiting on a conditional variable with a timeout does not
87 fn check_conditional_variables_timed_wait_timeout() {
88 let lock = Mutex::new(());
89 let cvar = Condvar::new();
90 let guard = lock.lock().unwrap();
91 let now = Instant::now();
92 let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
93 assert!(timeout.timed_out());
94 let elapsed_time = now.elapsed().as_millis();
95 assert!(100 <= elapsed_time && elapsed_time <= 300);
98 /// Test that signaling a conditional variable when waiting with a timeout works
100 fn check_conditional_variables_timed_wait_notimeout() {
101 let pair = Arc::new((Mutex::new(()), Condvar::new()));
102 let pair2 = pair.clone();
104 let (lock, cvar) = &*pair;
105 let guard = lock.lock().unwrap();
107 let handle = thread::spawn(move || {
108 let (_lock, cvar) = &*pair2;
112 let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(200)).unwrap();
113 assert!(!timeout.timed_out());
114 handle.join().unwrap();
117 // Check if locks are working.
120 let data = Arc::new(Mutex::new(0));
121 let mut threads = Vec::new();
124 let data = Arc::clone(&data);
125 let thread = thread::spawn(move || {
126 let mut data = data.lock().unwrap();
130 threads.push(thread);
133 for thread in threads {
134 thread.join().unwrap();
137 assert!(data.try_lock().is_ok());
139 let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
143 fn check_rwlock_write() {
144 let data = Arc::new(RwLock::new(0));
145 let mut threads = Vec::new();
148 let data = Arc::clone(&data);
149 let thread = thread::spawn(move || {
150 let mut data = data.write().unwrap();
154 threads.push(thread);
157 for thread in threads {
158 thread.join().unwrap();
161 assert!(data.try_write().is_ok());
163 let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
167 fn check_rwlock_read_no_deadlock() {
168 let l1 = Arc::new(RwLock::new(0));
169 let l2 = Arc::new(RwLock::new(0));
171 let l1_copy = Arc::clone(&l1);
172 let l2_copy = Arc::clone(&l2);
173 let _guard1 = l1.read().unwrap();
174 let handle = thread::spawn(move || {
175 let _guard2 = l2_copy.read().unwrap();
177 let _guard1 = l1_copy.read().unwrap();
180 let _guard2 = l2.read().unwrap();
181 handle.join().unwrap();
184 // Check if channels are working.
186 /// The test taken from the Rust documentation.
188 let (tx, rx) = channel();
189 thread::spawn(move || {
190 tx.send(10).unwrap();
192 assert_eq!(rx.recv().unwrap(), 10);
195 /// The test taken from the Rust documentation.
197 let (tx, rx) = channel();
200 thread::spawn(move || {
207 let j = rx.recv().unwrap();
208 assert!(0 <= j && j < 10);
214 /// The test taken from the Rust documentation.
216 let (sender, receiver) = sync_channel(1);
218 // this returns immediately
219 sender.send(1).unwrap();
221 thread::spawn(move || {
222 // this will block until the previous message has been received
223 sender.send(2).unwrap();
226 assert_eq!(receiver.recv().unwrap(), 1);
227 assert_eq!(receiver.recv().unwrap(), 2);
230 // Check if Rust once statics are working.
232 static mut VAL: usize = 0;
233 static INIT: Once = Once::new();
235 fn get_cached_val() -> usize {
238 VAL = expensive_computation();
244 fn expensive_computation() -> usize {
254 /// The test taken from the Rust documentation.
256 let handles: Vec<_> = (0..10)
260 let val = get_cached_val();
261 assert_eq!(val, 5040);
265 for handle in handles {
266 handle.join().unwrap();
270 fn check_rwlock_unlock_bug1() {
271 // There was a bug where when un-read-locking an rwlock that still has other
272 // readers waiting, we'd accidentally also let a writer in.
273 // That caused an ICE.
274 let l = Arc::new(RwLock::new(0));
276 let r1 = l.read().unwrap();
277 let r2 = l.read().unwrap();
279 // Make a waiting writer.
281 thread::spawn(move || {
282 let mut w = l2.write().unwrap();
296 fn check_rwlock_unlock_bug2() {
297 // There was a bug where when un-read-locking an rwlock by letting the last reader leaver,
298 // we'd forget to wake up a writer.
299 // That meant the writer thread could never run again.
300 let l = Arc::new(RwLock::new(0));
302 let r = l.read().unwrap();
304 // Make a waiting writer.
306 let h = thread::spawn(move || {
307 let _w = l2.write().unwrap();
316 let start = Instant::now();
318 thread::park_timeout(Duration::from_millis(200));
319 // Normally, waiting in park/park_timeout may spuriously wake up early, but we
320 // know Miri's timed synchronization primitives do not do that.
322 assert!((200..500).contains(&start.elapsed().as_millis()));
326 let t1 = thread::current();
327 let t2 = thread::spawn(move || {
329 thread::sleep(Duration::from_millis(200));
333 let start = Instant::now();
335 t2.thread().unpark();
337 // Normally, waiting in park/park_timeout may spuriously wake up early, but we
338 // know Miri's timed synchronization primitives do not do that.
340 assert!((200..500).contains(&start.elapsed().as_millis()));
345 check_conditional_variables_notify_one();
346 check_conditional_variables_notify_all();
347 check_conditional_variables_timed_wait_timeout();
348 check_conditional_variables_timed_wait_notimeout();
350 check_rwlock_write();
351 check_rwlock_read_no_deadlock();
356 check_rwlock_unlock_bug1();
357 check_rwlock_unlock_bug2();