1 //@ignore-target-windows: Concurrency on Windows is not supported yet.
2 //@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance
4 use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
6 use std::time::{Duration, Instant};
8 // Check if Rust barriers are working.
10 /// This test is taken from the Rust documentation.
12 let mut handles = Vec::with_capacity(10);
13 let barrier = Arc::new(Barrier::new(10));
15 let c = barrier.clone();
16 // The same messages will be printed together.
17 // You will NOT see any interleaving.
18 handles.push(thread::spawn(move || {
19 println!("before wait");
21 println!("after wait");
24 // Wait for other threads to finish.
25 for handle in handles {
26 handle.join().unwrap();
30 // Check if Rust conditional variables are working.
32 /// The test taken from the Rust documentation.
33 fn check_conditional_variables_notify_one() {
34 let pair = Arc::new((Mutex::new(false), Condvar::new()));
35 let pair2 = pair.clone();
37 // Spawn a new thread.
38 let t = thread::spawn(move || {
40 let (lock, cvar) = &*pair2;
41 let mut started = lock.lock().unwrap();
43 // We notify the condvar that the value has changed.
47 // Wait for the thread to fully start up.
48 let (lock, cvar) = &*pair;
49 let mut started = lock.lock().unwrap();
51 started = cvar.wait(started).unwrap();
57 /// Test that waiting on a conditional variable with a timeout does not
59 fn check_conditional_variables_timed_wait_timeout() {
60 let lock = Mutex::new(());
61 let cvar = Condvar::new();
62 let guard = lock.lock().unwrap();
63 let now = Instant::now();
64 let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
65 assert!(timeout.timed_out());
66 let elapsed_time = now.elapsed().as_millis();
67 assert!(100 <= elapsed_time && elapsed_time <= 1000);
70 /// Test that signaling a conditional variable when waiting with a timeout works
72 fn check_conditional_variables_timed_wait_notimeout() {
73 let pair = Arc::new((Mutex::new(()), Condvar::new()));
74 let pair2 = pair.clone();
76 let (lock, cvar) = &*pair;
77 let guard = lock.lock().unwrap();
79 let handle = thread::spawn(move || {
80 let (_lock, cvar) = &*pair2;
84 let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(1000)).unwrap();
85 assert!(!timeout.timed_out());
86 handle.join().unwrap();
89 // Check if locks are working.
92 let data = Arc::new(Mutex::new(0));
93 let mut threads = Vec::new();
96 let data = Arc::clone(&data);
97 let thread = thread::spawn(move || {
98 let mut data = data.lock().unwrap();
102 threads.push(thread);
105 for thread in threads {
106 thread.join().unwrap();
109 assert!(data.try_lock().is_ok());
111 let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
115 fn check_rwlock_write() {
116 let data = Arc::new(RwLock::new(0));
117 let mut threads = Vec::new();
120 let data = Arc::clone(&data);
121 let thread = thread::spawn(move || {
122 let mut data = data.write().unwrap();
126 threads.push(thread);
129 for thread in threads {
130 thread.join().unwrap();
133 assert!(data.try_write().is_ok());
135 let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
139 fn check_rwlock_read_no_deadlock() {
140 let l1 = Arc::new(RwLock::new(0));
141 let l2 = Arc::new(RwLock::new(0));
143 let l1_copy = Arc::clone(&l1);
144 let l2_copy = Arc::clone(&l2);
145 let _guard1 = l1.read().unwrap();
146 let handle = thread::spawn(move || {
147 let _guard2 = l2_copy.read().unwrap();
149 let _guard1 = l1_copy.read().unwrap();
152 let _guard2 = l2.read().unwrap();
153 handle.join().unwrap();
156 // Check if Rust once statics are working.
158 static mut VAL: usize = 0;
159 static INIT: Once = Once::new();
161 fn get_cached_val() -> usize {
164 VAL = expensive_computation();
170 fn expensive_computation() -> usize {
180 /// The test taken from the Rust documentation.
182 let handles: Vec<_> = (0..10)
186 let val = get_cached_val();
187 assert_eq!(val, 5040);
191 for handle in handles {
192 handle.join().unwrap();
197 let start = Instant::now();
199 thread::park_timeout(Duration::from_millis(200));
200 // Normally, waiting in park/park_timeout may spuriously wake up early, but we
201 // know Miri's timed synchronization primitives do not do that.
203 assert!((200..1000).contains(&start.elapsed().as_millis()));
207 let t1 = thread::current();
208 let t2 = thread::spawn(move || {
210 thread::sleep(Duration::from_millis(200));
214 let start = Instant::now();
216 t2.thread().unpark();
218 // Normally, waiting in park/park_timeout may spuriously wake up early, but we
219 // know Miri's timed synchronization primitives do not do that.
221 assert!((200..1000).contains(&start.elapsed().as_millis()));
228 check_conditional_variables_notify_one();
229 check_conditional_variables_timed_wait_timeout();
230 check_conditional_variables_timed_wait_notimeout();
232 check_rwlock_write();
233 check_rwlock_read_no_deadlock();