@@ -92,18 +92,27 @@ pub enum ThreadState {
92
92
Terminated ,
93
93
}
94
94
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
+
95
107
/// A thread.
96
108
pub struct Thread < ' mir , ' tcx > {
97
109
state : ThreadState ,
98
110
/// Name of the thread.
99
111
thread_name : Option < Vec < u8 > > ,
100
112
/// The virtual call stack.
101
113
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 ,
107
116
}
108
117
109
118
impl < ' mir , ' tcx > Thread < ' mir , ' tcx > {
@@ -128,7 +137,12 @@ impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> {
128
137
129
138
impl < ' mir , ' tcx > Default for Thread < ' mir , ' tcx > {
130
139
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
+ }
132
146
}
133
147
}
134
148
@@ -225,25 +239,31 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
225
239
226
240
/// Mark the thread as detached, which means that no other thread will try
227
241
/// 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 ( ( ) )
230
248
}
231
249
232
250
/// Mark that the active thread tries to join the thread with `joined_thread_id`.
233
251
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" ) ;
236
254
}
237
255
if joined_thread_id == self . active_thread {
238
256
throw_ub_format ! ( "trying to join itself" ) ;
239
257
}
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 ;
247
267
if self . threads [ joined_thread_id] . state != ThreadState :: Terminated {
248
268
// The joined thread is still running, we need to wait for it.
249
269
self . active_thread_mut ( ) . state = ThreadState :: BlockedOnJoin ( joined_thread_id) ;
@@ -451,8 +471,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
451
471
#[ inline]
452
472
fn detach_thread ( & mut self , thread_id : ThreadId ) -> InterpResult < ' tcx > {
453
473
let this = self . eval_context_mut ( ) ;
454
- this. machine . threads . detach_thread ( thread_id) ;
455
- Ok ( ( ) )
474
+ this. machine . threads . detach_thread ( thread_id)
456
475
}
457
476
458
477
#[ inline]
0 commit comments