]> git.lizzy.rs Git - rust.git/blob - tests/run-pass/concurrency/sync.rs
merge parking test into general synchronization test
[rust.git] / tests / run-pass / concurrency / sync.rs
1 // ignore-windows: Concurrency on Windows is not supported yet.
2 // compile-flags: -Zmiri-disable-isolation
3
4 use std::sync::mpsc::{channel, sync_channel};
5 use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
6 use std::thread;
7 use std::time::{Duration, Instant};
8
9 // Check if Rust barriers are working.
10
11 /// This test is taken from the Rust documentation.
12 fn check_barriers() {
13     let mut handles = Vec::with_capacity(10);
14     let barrier = Arc::new(Barrier::new(10));
15     for _ in 0..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");
21             c.wait();
22             println!("after wait");
23         }));
24     }
25     // Wait for other threads to finish.
26     for handle in handles {
27         handle.join().unwrap();
28     }
29 }
30
31 // Check if Rust conditional variables are working.
32
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();
37
38     // Spawn a new thread.
39     thread::spawn(move || {
40         thread::yield_now();
41         let (lock, cvar) = &*pair2;
42         let mut started = lock.lock().unwrap();
43         *started = true;
44         // We notify the condvar that the value has changed.
45         cvar.notify_one();
46     });
47
48     // Wait for the thread to fully start up.
49     let (lock, cvar) = &*pair;
50     let mut started = lock.lock().unwrap();
51     while !*started {
52         started = cvar.wait(started).unwrap();
53     }
54 }
55
56 fn check_conditional_variables_notify_all() {
57     let pair = Arc::new(((Mutex::new(())), Condvar::new()));
58
59     // Spawn threads and block them on the conditional variable.
60     let handles: Vec<_> = (0..5)
61         .map(|_| {
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();
68             })
69         })
70         .inspect(|_| {
71             thread::yield_now();
72             thread::yield_now();
73         })
74         .collect();
75
76     let (_, cvar) = &*pair;
77     // Unblock all threads.
78     cvar.notify_all();
79
80     for handle in handles {
81         handle.join().unwrap();
82     }
83 }
84
85 /// Test that waiting on a conditional variable with a timeout does not
86 /// deadlock.
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);
96 }
97
98 /// Test that signaling a conditional variable when waiting with a timeout works
99 /// as expected.
100 fn check_conditional_variables_timed_wait_notimeout() {
101     let pair = Arc::new((Mutex::new(()), Condvar::new()));
102     let pair2 = pair.clone();
103
104     let (lock, cvar) = &*pair;
105     let guard = lock.lock().unwrap();
106
107     let handle = thread::spawn(move || {
108         let (_lock, cvar) = &*pair2;
109         cvar.notify_one();
110     });
111
112     let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(200)).unwrap();
113     assert!(!timeout.timed_out());
114     handle.join().unwrap();
115 }
116
117 // Check if locks are working.
118
119 fn check_mutex() {
120     let data = Arc::new(Mutex::new(0));
121     let mut threads = Vec::new();
122
123     for _ in 0..3 {
124         let data = Arc::clone(&data);
125         let thread = thread::spawn(move || {
126             let mut data = data.lock().unwrap();
127             thread::yield_now();
128             *data += 1;
129         });
130         threads.push(thread);
131     }
132
133     for thread in threads {
134         thread.join().unwrap();
135     }
136
137     assert!(data.try_lock().is_ok());
138
139     let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
140     assert_eq!(data, 3);
141 }
142
143 fn check_rwlock_write() {
144     let data = Arc::new(RwLock::new(0));
145     let mut threads = Vec::new();
146
147     for _ in 0..3 {
148         let data = Arc::clone(&data);
149         let thread = thread::spawn(move || {
150             let mut data = data.write().unwrap();
151             thread::yield_now();
152             *data += 1;
153         });
154         threads.push(thread);
155     }
156
157     for thread in threads {
158         thread.join().unwrap();
159     }
160
161     assert!(data.try_write().is_ok());
162
163     let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
164     assert_eq!(data, 3);
165 }
166
167 fn check_rwlock_read_no_deadlock() {
168     let l1 = Arc::new(RwLock::new(0));
169     let l2 = Arc::new(RwLock::new(0));
170
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();
176         thread::yield_now();
177         let _guard1 = l1_copy.read().unwrap();
178     });
179     thread::yield_now();
180     let _guard2 = l2.read().unwrap();
181     handle.join().unwrap();
182 }
183
184 // Check if channels are working.
185
186 /// The test taken from the Rust documentation.
187 fn simple_send() {
188     let (tx, rx) = channel();
189     thread::spawn(move || {
190         tx.send(10).unwrap();
191     });
192     assert_eq!(rx.recv().unwrap(), 10);
193 }
194
195 /// The test taken from the Rust documentation.
196 fn multiple_send() {
197     let (tx, rx) = channel();
198     for i in 0..10 {
199         let tx = tx.clone();
200         thread::spawn(move || {
201             tx.send(i).unwrap();
202         });
203     }
204
205     let mut sum = 0;
206     for _ in 0..10 {
207         let j = rx.recv().unwrap();
208         assert!(0 <= j && j < 10);
209         sum += j;
210     }
211     assert_eq!(sum, 45);
212 }
213
214 /// The test taken from the Rust documentation.
215 fn send_on_sync() {
216     let (sender, receiver) = sync_channel(1);
217
218     // this returns immediately
219     sender.send(1).unwrap();
220
221     thread::spawn(move || {
222         // this will block until the previous message has been received
223         sender.send(2).unwrap();
224     });
225
226     assert_eq!(receiver.recv().unwrap(), 1);
227     assert_eq!(receiver.recv().unwrap(), 2);
228 }
229
230 // Check if Rust once statics are working.
231
232 static mut VAL: usize = 0;
233 static INIT: Once = Once::new();
234
235 fn get_cached_val() -> usize {
236     unsafe {
237         INIT.call_once(|| {
238             VAL = expensive_computation();
239         });
240         VAL
241     }
242 }
243
244 fn expensive_computation() -> usize {
245     let mut i = 1;
246     let mut c = 1;
247     while i < 1000 {
248         i *= c;
249         c += 1;
250     }
251     i
252 }
253
254 /// The test taken from the Rust documentation.
255 fn check_once() {
256     let handles: Vec<_> = (0..10)
257         .map(|_| {
258             thread::spawn(|| {
259                 thread::yield_now();
260                 let val = get_cached_val();
261                 assert_eq!(val, 5040);
262             })
263         })
264         .collect();
265     for handle in handles {
266         handle.join().unwrap();
267     }
268 }
269
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));
275
276     let r1 = l.read().unwrap();
277     let r2 = l.read().unwrap();
278
279     // Make a waiting writer.
280     let l2 = l.clone();
281     thread::spawn(move || {
282         let mut w = l2.write().unwrap();
283         *w += 1;
284     });
285     thread::yield_now();
286
287     drop(r1);
288     assert_eq!(*r2, 0);
289     thread::yield_now();
290     thread::yield_now();
291     thread::yield_now();
292     assert_eq!(*r2, 0);
293     drop(r2);
294 }
295
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));
301
302     let r = l.read().unwrap();
303
304     // Make a waiting writer.
305     let l2 = l.clone();
306     let h = thread::spawn(move || {
307         let _w = l2.write().unwrap();
308     });
309     thread::yield_now();
310
311     drop(r);
312     h.join().unwrap();
313 }
314
315 fn park_timeout() {
316     let start = Instant::now();
317
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.
321
322     assert!((200..500).contains(&start.elapsed().as_millis()));
323 }
324
325 fn park_unpark() {
326     let t1 = thread::current();
327     let t2 = thread::spawn(move || {
328         thread::park();
329         thread::sleep(Duration::from_millis(200));
330         t1.unpark();
331     });
332
333     let start = Instant::now();
334
335     t2.thread().unpark();
336     thread::park();
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.
339
340     assert!((200..500).contains(&start.elapsed().as_millis()));
341 }
342
343 fn main() {
344     check_barriers();
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();
349     check_mutex();
350     check_rwlock_write();
351     check_rwlock_read_no_deadlock();
352     simple_send();
353     multiple_send();
354     send_on_sync();
355     check_once();
356     check_rwlock_unlock_bug1();
357     check_rwlock_unlock_bug2();
358     park_timeout();
359     park_unpark();
360 }