-
Notifications
You must be signed in to change notification settings - Fork 353
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #1532 - divergentdave:thread-panic-payload, r=RalfJung
Move panic payload state from Machine to Thread This PR moves the panic payload storage from the `Machine` state to per-thread state. Prior to this change, if one thread panicked while another was still unwinding, Miri would fail with `thread 'rustc' panicked at 'the panic runtime should avoid double-panics', src/shims/panic.rs:51:9`. I ran into this issue while prototyping a round-robin scheduler, but it's also reachable with the current scheduler and contrived programs that use blocking API calls to cause thread switching during unwinding. I wrote a test case along those lines for this change.
- Loading branch information
Showing
11 changed files
with
176 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
warning: thread support is experimental. For example, Miri does not detect data races yet. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// ignore-windows: Concurrency on Windows is not supported yet. | ||
|
||
//! Cause a panic in one thread while another thread is unwinding. This checks | ||
//! that separate threads have their own panicking state. | ||
use std::sync::{Arc, Condvar, Mutex}; | ||
use std::thread::{spawn, JoinHandle}; | ||
|
||
struct BlockOnDrop(Option<JoinHandle<()>>); | ||
|
||
impl BlockOnDrop { | ||
fn new(handle: JoinHandle<()>) -> BlockOnDrop { | ||
BlockOnDrop(Some(handle)) | ||
} | ||
} | ||
|
||
impl Drop for BlockOnDrop { | ||
fn drop(&mut self) { | ||
eprintln!("Thread 2 blocking on thread 1"); | ||
let _ = self.0.take().unwrap().join(); | ||
eprintln!("Thread 1 has exited"); | ||
} | ||
} | ||
|
||
fn main() { | ||
let t1_started_pair = Arc::new((Mutex::new(false), Condvar::new())); | ||
let t2_started_pair = Arc::new((Mutex::new(false), Condvar::new())); | ||
|
||
let t1_continue_mutex = Arc::new(Mutex::new(())); | ||
let t1_continue_guard = t1_continue_mutex.lock(); | ||
|
||
let t1 = { | ||
let t1_started_pair = t1_started_pair.clone(); | ||
let t1_continue_mutex = t1_continue_mutex.clone(); | ||
spawn(move || { | ||
eprintln!("Thread 1 starting, will block on mutex"); | ||
let (mutex, condvar) = &*t1_started_pair; | ||
*mutex.lock().unwrap() = true; | ||
condvar.notify_one(); | ||
|
||
drop(t1_continue_mutex.lock()); | ||
panic!("panic in thread 1"); | ||
}) | ||
}; | ||
|
||
// Wait for thread 1 to signal it has started. | ||
let (t1_started_mutex, t1_started_condvar) = &*t1_started_pair; | ||
let mut t1_started_guard = t1_started_mutex.lock().unwrap(); | ||
while !*t1_started_guard { | ||
t1_started_guard = t1_started_condvar.wait(t1_started_guard).unwrap(); | ||
} | ||
eprintln!("Thread 1 reported it has started"); | ||
// Thread 1 should now be blocked waiting on t1_continue_mutex. | ||
|
||
let t2 = { | ||
let t2_started_pair = t2_started_pair.clone(); | ||
let block_on_drop = BlockOnDrop::new(t1); | ||
spawn(move || { | ||
let _ = block_on_drop; | ||
|
||
let (mutex, condvar) = &*t2_started_pair; | ||
*mutex.lock().unwrap() = true; | ||
condvar.notify_one(); | ||
|
||
panic!("panic in thread 2"); | ||
}) | ||
}; | ||
|
||
// Wait for thread 2 to signal it has started. | ||
let (t2_started_mutex, t2_started_condvar) = &*t2_started_pair; | ||
let mut t2_started_guard = t2_started_mutex.lock().unwrap(); | ||
while !*t2_started_guard { | ||
t2_started_guard = t2_started_condvar.wait(t2_started_guard).unwrap(); | ||
} | ||
eprintln!("Thread 2 reported it has started"); | ||
// Thread 2 should now have already panicked and be in the middle of | ||
// unwinding. It should now be blocked on joining thread 1. | ||
|
||
// Unlock t1_continue_mutex, and allow thread 1 to proceed. | ||
eprintln!("Unlocking mutex"); | ||
drop(t1_continue_guard); | ||
// Thread 1 will panic the next time it is scheduled. This will test the | ||
// behavior of interest to this test, whether Miri properly handles | ||
// concurrent panics in two different threads. | ||
|
||
// Block the main thread on waiting to join thread 2. Thread 2 should | ||
// already be blocked on joining thread 1, so thread 1 will be scheduled | ||
// to run next, as it is the only ready thread. | ||
assert!(t2.join().is_err()); | ||
eprintln!("Thread 2 has exited"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
warning: thread support is experimental. For example, Miri does not detect data races yet. | ||
|
||
Thread 1 starting, will block on mutex | ||
Thread 1 reported it has started | ||
thread '<unnamed>' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:65:13 | ||
Thread 2 blocking on thread 1 | ||
Thread 2 reported it has started | ||
Unlocking mutex | ||
thread '<unnamed>' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:42:13 | ||
Thread 1 has exited | ||
Thread 2 has exited |