@@ -90,7 +90,7 @@ impl From<ThreadId> for u64 {
9090}
9191
9292/// Keeps track of what the thread is blocked on.
93- #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
93+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
9494pub enum BlockReason {
9595 /// The thread tried to join the specified thread and is blocked until that
9696 /// thread terminates.
@@ -151,8 +151,8 @@ impl<'tcx> ThreadState<'tcx> {
151151 matches ! ( self , ThreadState :: Terminated )
152152 }
153153
154- fn is_blocked_on ( & self , reason : BlockReason ) -> bool {
155- matches ! ( * self , ThreadState :: Blocked { reason: actual_reason, .. } if actual_reason == reason)
154+ fn is_blocked_on ( & self , reason : & BlockReason ) -> bool {
155+ matches ! ( self , ThreadState :: Blocked { reason: actual_reason, .. } if actual_reason == reason)
156156 }
157157}
158158
@@ -421,9 +421,14 @@ pub enum TimeoutAnchor {
421421 Absolute ,
422422}
423423
424- /// An error signaling that the requested thread doesn't exist.
424+ /// An error signaling that the requested thread doesn't exist or has terminated .
425425#[ derive( Debug , Copy , Clone ) ]
426- pub struct ThreadNotFound ;
426+ pub enum ThreadLookupError {
427+ /// No thread with this ID exists.
428+ InvalidId ,
429+ /// The thread exists but has already terminated.
430+ Terminated ( ThreadId ) ,
431+ }
427432
428433/// A set of threads.
429434#[ derive( Debug ) ]
@@ -489,13 +494,21 @@ impl<'tcx> ThreadManager<'tcx> {
489494 }
490495 }
491496
492- pub fn thread_id_try_from ( & self , id : impl TryInto < u32 > ) -> Result < ThreadId , ThreadNotFound > {
497+ /// Returns the `ThreadId` for the given raw thread id.
498+ /// Returns `Err(ThreadNotFound::InvalidId)` if the id is out of range, or
499+ /// `Err(ThreadNotFound::Terminated(id))` if the thread exists but has terminated.
500+ pub fn thread_id_try_from ( & self , id : impl TryInto < u32 > ) -> Result < ThreadId , ThreadLookupError > {
493501 if let Ok ( id) = id. try_into ( )
494502 && usize:: try_from ( id) . is_ok_and ( |id| id < self . threads . len ( ) )
495503 {
496- Ok ( ThreadId ( id) )
504+ let thread_id = ThreadId ( id) ;
505+ if self . threads [ thread_id] . state . is_terminated ( ) {
506+ Err ( ThreadLookupError :: Terminated ( thread_id) )
507+ } else {
508+ Ok ( thread_id)
509+ }
497510 } else {
498- Err ( ThreadNotFound )
511+ Err ( ThreadLookupError :: InvalidId )
499512 }
500513 }
501514
@@ -696,7 +709,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
696709 // If a thread is blocked on GenMC, we have to implicitly unblock it when it gets scheduled again.
697710 if this. machine . threads . threads [ next_thread_id]
698711 . state
699- . is_blocked_on ( BlockReason :: Genmc )
712+ . is_blocked_on ( & BlockReason :: Genmc )
700713 {
701714 info ! (
702715 "GenMC: scheduling blocked thread {next_thread_id:?}, so we unblock it now."
@@ -798,7 +811,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
798811 } else if thread_manager
799812 . threads
800813 . iter ( )
801- . any ( |thread| thread. state . is_blocked_on ( BlockReason :: IO ) )
814+ . any ( |thread| thread. state . is_blocked_on ( & BlockReason :: IO ) )
802815 {
803816 // At least one thread is blocked on host I/O but doesn't
804817 // have a timeout set. Hence, we sleep indefinitely in the
@@ -884,7 +897,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
884897impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
885898pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
886899 #[ inline]
887- fn thread_id_try_from ( & self , id : impl TryInto < u32 > ) -> Result < ThreadId , ThreadNotFound > {
900+ fn thread_id_try_from ( & self , id : impl TryInto < u32 > ) -> Result < ThreadId , ThreadLookupError > {
888901 self . eval_context_ref ( ) . machine . threads . thread_id_try_from ( id)
889902 }
890903
@@ -1059,11 +1072,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10591072 let threads = & this. machine . threads . threads ;
10601073 let joining_threads = threads
10611074 . iter_enumerated ( )
1062- . filter ( |( _, thread) | thread. state . is_blocked_on ( unblock_reason) )
1075+ . filter ( |( _, thread) | thread. state . is_blocked_on ( & unblock_reason) )
10631076 . map ( |( id, _) | id)
10641077 . collect :: < Vec < _ > > ( ) ;
10651078 for thread in joining_threads {
1066- this. unblock_thread ( thread, unblock_reason) ?;
1079+ this. unblock_thread ( thread, unblock_reason. clone ( ) ) ?;
10671080 }
10681081
10691082 interp_ok ( ( ) )
@@ -1231,9 +1244,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
12311244
12321245 // Sanity check `join_status`.
12331246 assert ! (
1234- threads
1235- . iter ( )
1236- . all ( |thread| { !thread . state . is_blocked_on ( BlockReason :: Join ( joined_thread_id ) ) } ) ,
1247+ threads. iter ( ) . all ( |thread| {
1248+ !thread . state . is_blocked_on ( & BlockReason :: Join ( joined_thread_id ) )
1249+ } ) ,
12371250 "this thread already has threads waiting for its termination"
12381251 ) ;
12391252
0 commit comments