]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/tests/pass/panic/concurrent-panic.rs
Auto merge of #104915 - weihanglo:update-cargo, r=ehuss
[rust.git] / src / tools / miri / tests / pass / panic / concurrent-panic.rs
1 // We are making scheduler assumptions here.
2 //@compile-flags: -Zmiri-preemption-rate=0
3
4 //! Cause a panic in one thread while another thread is unwinding. This checks
5 //! that separate threads have their own panicking state.
6
7 use std::sync::{Arc, Condvar, Mutex};
8 use std::thread::{spawn, JoinHandle};
9
10 struct BlockOnDrop(Option<JoinHandle<()>>);
11
12 impl BlockOnDrop {
13     fn new(handle: JoinHandle<()>) -> BlockOnDrop {
14         BlockOnDrop(Some(handle))
15     }
16 }
17
18 impl Drop for BlockOnDrop {
19     fn drop(&mut self) {
20         eprintln!("Thread 2 blocking on thread 1");
21         let _ = self.0.take().unwrap().join();
22         eprintln!("Thread 1 has exited");
23     }
24 }
25
26 fn main() {
27     let t1_started_pair = Arc::new((Mutex::new(false), Condvar::new()));
28     let t2_started_pair = Arc::new((Mutex::new(false), Condvar::new()));
29
30     let t1_continue_mutex = Arc::new(Mutex::new(()));
31     let t1_continue_guard = t1_continue_mutex.lock();
32
33     let t1 = {
34         let t1_started_pair = t1_started_pair.clone();
35         let t1_continue_mutex = t1_continue_mutex.clone();
36         spawn(move || {
37             eprintln!("Thread 1 starting, will block on mutex");
38             let (mutex, condvar) = &*t1_started_pair;
39             *mutex.lock().unwrap() = true;
40             condvar.notify_one();
41
42             drop(t1_continue_mutex.lock());
43             panic!("panic in thread 1");
44         })
45     };
46
47     // Wait for thread 1 to signal it has started.
48     let (t1_started_mutex, t1_started_condvar) = &*t1_started_pair;
49     let mut t1_started_guard = t1_started_mutex.lock().unwrap();
50     while !*t1_started_guard {
51         t1_started_guard = t1_started_condvar.wait(t1_started_guard).unwrap();
52     }
53     eprintln!("Thread 1 reported it has started");
54     // Thread 1 should now be blocked waiting on t1_continue_mutex.
55
56     let t2 = {
57         let t2_started_pair = t2_started_pair.clone();
58         let block_on_drop = BlockOnDrop::new(t1);
59         spawn(move || {
60             let _ = block_on_drop;
61
62             let (mutex, condvar) = &*t2_started_pair;
63             *mutex.lock().unwrap() = true;
64             condvar.notify_one();
65
66             panic!("panic in thread 2");
67         })
68     };
69
70     // Wait for thread 2 to signal it has started.
71     let (t2_started_mutex, t2_started_condvar) = &*t2_started_pair;
72     let mut t2_started_guard = t2_started_mutex.lock().unwrap();
73     while !*t2_started_guard {
74         t2_started_guard = t2_started_condvar.wait(t2_started_guard).unwrap();
75     }
76     eprintln!("Thread 2 reported it has started");
77     // Thread 2 should now have already panicked and be in the middle of
78     // unwinding. It should now be blocked on joining thread 1.
79
80     // Unlock t1_continue_mutex, and allow thread 1 to proceed.
81     eprintln!("Unlocking mutex");
82     drop(t1_continue_guard);
83     // Thread 1 will panic the next time it is scheduled. This will test the
84     // behavior of interest to this test, whether Miri properly handles
85     // concurrent panics in two different threads.
86
87     // Block the main thread on waiting to join thread 2. Thread 2 should
88     // already be blocked on joining thread 1, so thread 1 will be scheduled
89     // to run next, as it is the only ready thread.
90     assert!(t2.join().is_err());
91     eprintln!("Thread 2 has exited");
92 }