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
/// 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
/// main thread. However, it is not clear that we should run the TLS
/// destructors for the main thread. See issue:
@ -367,6 +364,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// All dtors done!
this.machine.tls.delete_all_thread_tls(active_thread);
this.thread_terminated();
Ok(())
}

View File

@ -410,6 +410,20 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
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.
///
/// 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
// the thread state to 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);
}
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();
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 {
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()
.unwrap();
println!("Continue main.")
println!("Continue main 1.")
}
struct JoinCell {
@ -37,8 +38,9 @@ struct JoinCell {
impl Drop for JoinCell {
fn drop(&mut self) {
for _ in 0..10 { thread::yield_now(); }
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
Continue main.
Dropping: 5 (should be before 'Continue main 1').
Continue main 1.
Joining: 7 (should be before 'Continue main 2').
Continue main 2.
Joining: 7