fix and test order of TLS dtors and thread joining
This commit is contained in:
parent
390899e8b9
commit
2a42f8e93c
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user