Skip to content

Commit e4dc356

Browse files
author
Vytautas Astrauskas
committed
Track if a thread was already joined.
1 parent 5b55e07 commit e4dc356

File tree

1 file changed

+38
-19
lines changed

1 file changed

+38
-19
lines changed

src/thread.rs

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,27 @@ pub enum ThreadState {
9292
Terminated,
9393
}
9494

95+
/// The join status of a thread.
96+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
97+
enum ThreadJoinStatus {
98+
/// The thread can be joined.
99+
Joinable,
100+
/// A thread is detached if its join handle was destroyed and no other
101+
/// thread can join it.
102+
Detached,
103+
/// The thread was already joined by some thread and cannot be joined again.
104+
Joined,
105+
}
106+
95107
/// A thread.
96108
pub struct Thread<'mir, 'tcx> {
97109
state: ThreadState,
98110
/// Name of the thread.
99111
thread_name: Option<Vec<u8>>,
100112
/// The virtual call stack.
101113
stack: Vec<Frame<'mir, 'tcx, Tag, FrameData<'tcx>>>,
102-
/// Is the thread detached?
103-
///
104-
/// A thread is detached if its join handle was destroyed and no other
105-
/// thread can join it.
106-
detached: bool,
114+
/// The join status.
115+
join_status: ThreadJoinStatus,
107116
}
108117

109118
impl<'mir, 'tcx> Thread<'mir, 'tcx> {
@@ -128,7 +137,12 @@ impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> {
128137

129138
impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
130139
fn default() -> Self {
131-
Self { state: ThreadState::Enabled, thread_name: None, stack: Vec::new(), detached: false }
140+
Self {
141+
state: ThreadState::Enabled,
142+
thread_name: None,
143+
stack: Vec::new(),
144+
join_status: ThreadJoinStatus::Joinable,
145+
}
132146
}
133147
}
134148

@@ -225,25 +239,31 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
225239

226240
/// Mark the thread as detached, which means that no other thread will try
227241
/// to join it and the thread is responsible for cleaning up.
228-
fn detach_thread(&mut self, id: ThreadId) {
229-
self.threads[id].detached = true;
242+
fn detach_thread(&mut self, id: ThreadId) -> InterpResult<'tcx> {
243+
if self.threads[id].join_status != ThreadJoinStatus::Joinable {
244+
throw_ub_format!("trying to detach thread that was already detached or joined");
245+
}
246+
self.threads[id].join_status = ThreadJoinStatus::Detached;
247+
Ok(())
230248
}
231249

232250
/// Mark that the active thread tries to join the thread with `joined_thread_id`.
233251
fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> {
234-
if self.threads[joined_thread_id].detached {
235-
throw_ub_format!("trying to join a detached thread");
252+
if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable {
253+
throw_ub_format!("trying to join a detached or already joined thread");
236254
}
237255
if joined_thread_id == self.active_thread {
238256
throw_ub_format!("trying to join itself");
239257
}
240-
if self
241-
.threads
242-
.iter()
243-
.any(|thread| thread.state == ThreadState::BlockedOnJoin(joined_thread_id))
244-
{
245-
throw_ub_format!("multiple threads try to join the same thread");
246-
}
258+
assert!(
259+
self.threads
260+
.iter()
261+
.all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)),
262+
"a joinable thread has threads waiting for its termination"
263+
);
264+
// Mark the joined thread as being joined so that we detect if other
265+
// threads try to join it.
266+
self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined;
247267
if self.threads[joined_thread_id].state != ThreadState::Terminated {
248268
// The joined thread is still running, we need to wait for it.
249269
self.active_thread_mut().state = ThreadState::BlockedOnJoin(joined_thread_id);
@@ -451,8 +471,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
451471
#[inline]
452472
fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> {
453473
let this = self.eval_context_mut();
454-
this.machine.threads.detach_thread(thread_id);
455-
Ok(())
474+
this.machine.threads.detach_thread(thread_id)
456475
}
457476

458477
#[inline]

0 commit comments

Comments
 (0)