fix and test order of TLS dtors and thread joining

This commit is contained in:
Ralf Jung 2020-07-26 15:53:02 +02:00
parent 390899e8b9
commit 2a42f8e93c
4 changed files with 28 additions and 16 deletions

View File

@ -328,9 +328,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
/// schedules them one by one each time it is called and reenables the /// schedules them one by one each time it is called and reenables the
/// thread so that it can be executed normally by the main execution loop. /// thread so that it can be executed normally by the main execution loop.
/// ///
/// FIXME: we do not support yet deallocation of thread local statics.
/// Issue: https://github.com/rust-lang/miri/issues/1369
///
/// Note: we consistently run TLS destructors for all threads, including the /// Note: we consistently run TLS destructors for all threads, including the
/// main thread. However, it is not clear that we should run the TLS /// main thread. However, it is not clear that we should run the TLS
/// destructors for the main thread. See issue: /// destructors for the main thread. See issue:
@ -367,6 +364,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// All dtors done! // All dtors done!
this.machine.tls.delete_all_thread_tls(active_thread); this.machine.tls.delete_all_thread_tls(active_thread);
this.thread_terminated();
Ok(()) Ok(())
} }

View File

@ -410,6 +410,20 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
None None
} }
/// Handles thread termination of the active thread: wakes up threads joining on this one,
/// and deallocated thread-local statics.
///
/// This is called from `tls.rs` after handling the TLS dtors.
fn thread_terminated(&mut self) {
for (i, thread) in self.threads.iter_enumerated_mut() {
// Check if we need to unblock any threads.
if thread.state == ThreadState::BlockedOnJoin(self.active_thread) {
trace!("unblocking {:?} because {:?} terminated", i, self.active_thread);
thread.state = ThreadState::Enabled;
}
}
}
/// Decide which action to take next and on which thread. /// Decide which action to take next and on which thread.
/// ///
/// The currently implemented scheduling policy is the one that is commonly /// The currently implemented scheduling policy is the one that is commonly
@ -421,13 +435,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
// checks whether the thread has popped all its stack and if yes, sets // checks whether the thread has popped all its stack and if yes, sets
// the thread state to terminated). // the thread state to terminated).
if self.threads[self.active_thread].check_terminated() { if self.threads[self.active_thread].check_terminated() {
// Check if we need to unblock any threads.
for (i, thread) in self.threads.iter_enumerated_mut() {
if thread.state == ThreadState::BlockedOnJoin(self.active_thread) {
trace!("unblocking {:?} because {:?} terminated", i, self.active_thread);
thread.state = ThreadState::Enabled;
}
}
return Ok(SchedulingAction::ExecuteDtors); return Ok(SchedulingAction::ExecuteDtors);
} }
if self.threads[MAIN_THREAD].state == ThreadState::Terminated { if self.threads[MAIN_THREAD].state == ThreadState::Terminated {
@ -660,4 +667,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.machine.threads.schedule() this.machine.threads.schedule()
} }
#[inline]
fn thread_terminated(&mut self) {
self.eval_context_mut().machine.threads.thread_terminated()
}
} }

View File

@ -9,7 +9,8 @@ struct TestCell {
impl Drop for TestCell { impl Drop for TestCell {
fn drop(&mut self) { fn drop(&mut self) {
println!("Dropping: {}", self.value.borrow()) for _ in 0..10 { thread::yield_now(); }
println!("Dropping: {} (should be before 'Continue main 1').", self.value.borrow())
} }
} }
@ -28,7 +29,7 @@ fn check_destructors() {
}) })
.join() .join()
.unwrap(); .unwrap();
println!("Continue main.") println!("Continue main 1.")
} }
struct JoinCell { struct JoinCell {
@ -37,8 +38,9 @@ struct JoinCell {
impl Drop for JoinCell { impl Drop for JoinCell {
fn drop(&mut self) { fn drop(&mut self) {
for _ in 0..10 { thread::yield_now(); }
let join_handle = self.value.borrow_mut().take().unwrap(); let join_handle = self.value.borrow_mut().take().unwrap();
println!("Joining: {}", join_handle.join().unwrap()); println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap());
} }
} }

View File

@ -1,4 +1,4 @@
Dropping: 5 Dropping: 5 (should be before 'Continue main 1').
Continue main. Continue main 1.
Joining: 7 (should be before 'Continue main 2').
Continue main 2. Continue main 2.
Joining: 7