1 // We are making scheduler assumptions here.
2 //@compile-flags: -Zmiri-preemption-rate=0
4 //! Cause a panic in one thread while another thread is unwinding. This checks
5 //! that separate threads have their own panicking state.
7 use std::sync::{Arc, Condvar, Mutex};
8 use std::thread::{spawn, JoinHandle};
10 struct BlockOnDrop(Option<JoinHandle<()>>);
13 fn new(handle: JoinHandle<()>) -> BlockOnDrop {
14 BlockOnDrop(Some(handle))
18 impl Drop for BlockOnDrop {
20 eprintln!("Thread 2 blocking on thread 1");
21 let _ = self.0.take().unwrap().join();
22 eprintln!("Thread 1 has exited");
27 let t1_started_pair = Arc::new((Mutex::new(false), Condvar::new()));
28 let t2_started_pair = Arc::new((Mutex::new(false), Condvar::new()));
30 let t1_continue_mutex = Arc::new(Mutex::new(()));
31 let t1_continue_guard = t1_continue_mutex.lock();
34 let t1_started_pair = t1_started_pair.clone();
35 let t1_continue_mutex = t1_continue_mutex.clone();
37 eprintln!("Thread 1 starting, will block on mutex");
38 let (mutex, condvar) = &*t1_started_pair;
39 *mutex.lock().unwrap() = true;
42 drop(t1_continue_mutex.lock());
43 panic!("panic in thread 1");
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();
53 eprintln!("Thread 1 reported it has started");
54 // Thread 1 should now be blocked waiting on t1_continue_mutex.
57 let t2_started_pair = t2_started_pair.clone();
58 let block_on_drop = BlockOnDrop::new(t1);
60 let _ = block_on_drop;
62 let (mutex, condvar) = &*t2_started_pair;
63 *mutex.lock().unwrap() = true;
66 panic!("panic in thread 2");
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();
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.
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.
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");