]> git.lizzy.rs Git - rust.git/blob - src/thread.rs
adjust Miri to Pointer type overhaul
[rust.git] / src / thread.rs
1 //! Implements threads.
2
3 use std::cell::RefCell;
4 use std::collections::hash_map::Entry;
5 use std::convert::TryFrom;
6 use std::num::TryFromIntError;
7 use std::time::{Duration, Instant, SystemTime};
8
9 use log::trace;
10
11 use rustc_data_structures::fx::FxHashMap;
12 use rustc_hir::def_id::DefId;
13 use rustc_index::vec::{Idx, IndexVec};
14
15 use crate::sync::SynchronizationState;
16 use crate::*;
17
18 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
19 pub enum SchedulingAction {
20     /// Execute step on the active thread.
21     ExecuteStep,
22     /// Execute a timeout callback.
23     ExecuteTimeoutCallback,
24     /// Execute destructors of the active thread.
25     ExecuteDtors,
26     /// Stop the program.
27     Stop,
28 }
29
30 /// Timeout callbacks can be created by synchronization primitives to tell the
31 /// scheduler that they should be called once some period of time passes.
32 type TimeoutCallback<'mir, 'tcx> =
33     Box<dyn FnOnce(&mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>) -> InterpResult<'tcx> + 'tcx>;
34
35 /// A thread identifier.
36 #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
37 pub struct ThreadId(u32);
38
39 /// The main thread. When it terminates, the whole application terminates.
40 const MAIN_THREAD: ThreadId = ThreadId(0);
41
42 impl ThreadId {
43     pub fn to_u32(self) -> u32 {
44         self.0
45     }
46 }
47
48 impl Idx for ThreadId {
49     fn new(idx: usize) -> Self {
50         ThreadId(u32::try_from(idx).unwrap())
51     }
52
53     fn index(self) -> usize {
54         usize::try_from(self.0).unwrap()
55     }
56 }
57
58 impl TryFrom<u64> for ThreadId {
59     type Error = TryFromIntError;
60     fn try_from(id: u64) -> Result<Self, Self::Error> {
61         u32::try_from(id).map(|id_u32| Self(id_u32))
62     }
63 }
64
65 impl From<u32> for ThreadId {
66     fn from(id: u32) -> Self {
67         Self(id)
68     }
69 }
70
71 impl ThreadId {
72     pub fn to_u32_scalar<'tcx>(&self) -> Scalar<Tag> {
73         Scalar::from_u32(u32::try_from(self.0).unwrap())
74     }
75 }
76
77 /// The state of a thread.
78 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
79 pub enum ThreadState {
80     /// The thread is enabled and can be executed.
81     Enabled,
82     /// The thread tried to join the specified thread and is blocked until that
83     /// thread terminates.
84     BlockedOnJoin(ThreadId),
85     /// The thread is blocked on some synchronization primitive. It is the
86     /// responsibility of the synchronization primitives to track threads that
87     /// are blocked by them.
88     BlockedOnSync,
89     /// The thread has terminated its execution. We do not delete terminated
90     /// threads (FIXME: why?).
91     Terminated,
92 }
93
94 /// The join status of a thread.
95 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
96 enum ThreadJoinStatus {
97     /// The thread can be joined.
98     Joinable,
99     /// A thread is detached if its join handle was destroyed and no other
100     /// thread can join it.
101     Detached,
102     /// The thread was already joined by some thread and cannot be joined again.
103     Joined,
104 }
105
106 /// A thread.
107 pub struct Thread<'mir, 'tcx> {
108     state: ThreadState,
109
110     /// Name of the thread.
111     thread_name: Option<Vec<u8>>,
112
113     /// The virtual call stack.
114     stack: Vec<Frame<'mir, 'tcx, Tag, FrameData<'tcx>>>,
115
116     /// The join status.
117     join_status: ThreadJoinStatus,
118
119     /// The temporary used for storing the argument of
120     /// the call to `miri_start_panic` (the panic payload) when unwinding.
121     /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`.
122     pub(crate) panic_payload: Option<Scalar<Tag>>,
123
124     /// Last OS error location in memory. It is a 32-bit integer.
125     pub(crate) last_error: Option<MPlaceTy<'tcx, Tag>>,
126 }
127
128 impl<'mir, 'tcx> Thread<'mir, 'tcx> {
129     /// Check if the thread is done executing (no more stack frames). If yes,
130     /// change the state to terminated and return `true`.
131     fn check_terminated(&mut self) -> bool {
132         if self.state == ThreadState::Enabled {
133             if self.stack.is_empty() {
134                 self.state = ThreadState::Terminated;
135                 return true;
136             }
137         }
138         false
139     }
140
141     /// Get the name of the current thread, or `<unnamed>` if it was not set.
142     fn thread_name(&self) -> &[u8] {
143         if let Some(ref thread_name) = self.thread_name { thread_name } else { b"<unnamed>" }
144     }
145 }
146
147 impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> {
148     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149         write!(
150             f,
151             "{}({:?}, {:?})",
152             String::from_utf8_lossy(self.thread_name()),
153             self.state,
154             self.join_status
155         )
156     }
157 }
158
159 impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
160     fn default() -> Self {
161         Self {
162             state: ThreadState::Enabled,
163             thread_name: None,
164             stack: Vec::new(),
165             join_status: ThreadJoinStatus::Joinable,
166             panic_payload: None,
167             last_error: None,
168         }
169     }
170 }
171
172 /// A specific moment in time.
173 #[derive(Debug)]
174 pub enum Time {
175     Monotonic(Instant),
176     RealTime(SystemTime),
177 }
178
179 impl Time {
180     /// How long do we have to wait from now until the specified time?
181     fn get_wait_time(&self) -> Duration {
182         match self {
183             Time::Monotonic(instant) => instant.saturating_duration_since(Instant::now()),
184             Time::RealTime(time) =>
185                 time.duration_since(SystemTime::now()).unwrap_or(Duration::new(0, 0)),
186         }
187     }
188 }
189
190 /// Callbacks are used to implement timeouts. For example, waiting on a
191 /// conditional variable with a timeout creates a callback that is called after
192 /// the specified time and unblocks the thread. If another thread signals on the
193 /// conditional variable, the signal handler deletes the callback.
194 struct TimeoutCallbackInfo<'mir, 'tcx> {
195     /// The callback should be called no earlier than this time.
196     call_time: Time,
197     /// The called function.
198     callback: TimeoutCallback<'mir, 'tcx>,
199 }
200
201 impl<'mir, 'tcx> std::fmt::Debug for TimeoutCallbackInfo<'mir, 'tcx> {
202     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203         write!(f, "TimeoutCallback({:?})", self.call_time)
204     }
205 }
206
207 /// A set of threads.
208 #[derive(Debug)]
209 pub struct ThreadManager<'mir, 'tcx> {
210     /// Identifier of the currently active thread.
211     active_thread: ThreadId,
212     /// Threads used in the program.
213     ///
214     /// Note that this vector also contains terminated threads.
215     threads: IndexVec<ThreadId, Thread<'mir, 'tcx>>,
216     /// This field is pub(crate) because the synchronization primitives
217     /// (`crate::sync`) need a way to access it.
218     pub(crate) sync: SynchronizationState,
219     /// A mapping from a thread-local static to an allocation id of a thread
220     /// specific allocation.
221     thread_local_alloc_ids: RefCell<FxHashMap<(DefId, ThreadId), Pointer<Tag>>>,
222     /// A flag that indicates that we should change the active thread.
223     yield_active_thread: bool,
224     /// Callbacks that are called once the specified time passes.
225     timeout_callbacks: FxHashMap<ThreadId, TimeoutCallbackInfo<'mir, 'tcx>>,
226 }
227
228 impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
229     fn default() -> Self {
230         let mut threads = IndexVec::new();
231         // Create the main thread and add it to the list of threads.
232         let mut main_thread = Thread::default();
233         // The main thread can *not* be joined on.
234         main_thread.join_status = ThreadJoinStatus::Detached;
235         threads.push(main_thread);
236         Self {
237             active_thread: ThreadId::new(0),
238             threads: threads,
239             sync: SynchronizationState::default(),
240             thread_local_alloc_ids: Default::default(),
241             yield_active_thread: false,
242             timeout_callbacks: FxHashMap::default(),
243         }
244     }
245 }
246
247 impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
248     /// Check if we have an allocation for the given thread local static for the
249     /// active thread.
250     fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option<Pointer<Tag>> {
251         self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned()
252     }
253
254     /// Set the pointer for the allocation of the given thread local
255     /// static for the active thread.
256     ///
257     /// Panics if a thread local is initialized twice for the same thread.
258     fn set_thread_local_alloc(&self, def_id: DefId, ptr: Pointer<Tag>) {
259         self.thread_local_alloc_ids
260             .borrow_mut()
261             .try_insert((def_id, self.active_thread), ptr)
262             .unwrap();
263     }
264
265     /// Borrow the stack of the active thread.
266     fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] {
267         &self.threads[self.active_thread].stack
268     }
269
270     /// Mutably borrow the stack of the active thread.
271     fn active_thread_stack_mut(&mut self) -> &mut Vec<Frame<'mir, 'tcx, Tag, FrameData<'tcx>>> {
272         &mut self.threads[self.active_thread].stack
273     }
274
275     /// Create a new thread and returns its id.
276     fn create_thread(&mut self) -> ThreadId {
277         let new_thread_id = ThreadId::new(self.threads.len());
278         self.threads.push(Default::default());
279         new_thread_id
280     }
281
282     /// Set an active thread and return the id of the thread that was active before.
283     fn set_active_thread_id(&mut self, id: ThreadId) -> ThreadId {
284         let active_thread_id = self.active_thread;
285         self.active_thread = id;
286         assert!(self.active_thread.index() < self.threads.len());
287         active_thread_id
288     }
289
290     /// Get the id of the currently active thread.
291     fn get_active_thread_id(&self) -> ThreadId {
292         self.active_thread
293     }
294
295     /// Get the total number of threads that were ever spawn by this program.
296     fn get_total_thread_count(&self) -> usize {
297         self.threads.len()
298     }
299
300     /// Has the given thread terminated?
301     fn has_terminated(&self, thread_id: ThreadId) -> bool {
302         self.threads[thread_id].state == ThreadState::Terminated
303     }
304
305     /// Enable the thread for execution. The thread must be terminated.
306     fn enable_thread(&mut self, thread_id: ThreadId) {
307         assert!(self.has_terminated(thread_id));
308         self.threads[thread_id].state = ThreadState::Enabled;
309     }
310
311     /// Get a mutable borrow of the currently active thread.
312     fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> {
313         &mut self.threads[self.active_thread]
314     }
315
316     /// Get a shared borrow of the currently active thread.
317     fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> {
318         &self.threads[self.active_thread]
319     }
320
321     /// Mark the thread as detached, which means that no other thread will try
322     /// to join it and the thread is responsible for cleaning up.
323     fn detach_thread(&mut self, id: ThreadId) -> InterpResult<'tcx> {
324         if self.threads[id].join_status != ThreadJoinStatus::Joinable {
325             throw_ub_format!("trying to detach thread that was already detached or joined");
326         }
327         self.threads[id].join_status = ThreadJoinStatus::Detached;
328         Ok(())
329     }
330
331     /// Mark that the active thread tries to join the thread with `joined_thread_id`.
332     fn join_thread(
333         &mut self,
334         joined_thread_id: ThreadId,
335         data_race: Option<&mut data_race::GlobalState>,
336     ) -> InterpResult<'tcx> {
337         if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable {
338             throw_ub_format!("trying to join a detached or already joined thread");
339         }
340         if joined_thread_id == self.active_thread {
341             throw_ub_format!("trying to join itself");
342         }
343         assert!(
344             self.threads
345                 .iter()
346                 .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)),
347             "a joinable thread already has threads waiting for its termination"
348         );
349         // Mark the joined thread as being joined so that we detect if other
350         // threads try to join it.
351         self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined;
352         if self.threads[joined_thread_id].state != ThreadState::Terminated {
353             // The joined thread is still running, we need to wait for it.
354             self.active_thread_mut().state = ThreadState::BlockedOnJoin(joined_thread_id);
355             trace!(
356                 "{:?} blocked on {:?} when trying to join",
357                 self.active_thread,
358                 joined_thread_id
359             );
360         } else {
361             // The thread has already terminated - mark join happens-before
362             if let Some(data_race) = data_race {
363                 data_race.thread_joined(self.active_thread, joined_thread_id);
364             }
365         }
366         Ok(())
367     }
368
369     /// Set the name of the active thread.
370     fn set_thread_name(&mut self, new_thread_name: Vec<u8>) {
371         self.active_thread_mut().thread_name = Some(new_thread_name);
372     }
373
374     /// Get the name of the active thread.
375     fn get_thread_name(&self) -> &[u8] {
376         self.active_thread_ref().thread_name()
377     }
378
379     /// Put the thread into the blocked state.
380     fn block_thread(&mut self, thread: ThreadId) {
381         let state = &mut self.threads[thread].state;
382         assert_eq!(*state, ThreadState::Enabled);
383         *state = ThreadState::BlockedOnSync;
384     }
385
386     /// Put the blocked thread into the enabled state.
387     fn unblock_thread(&mut self, thread: ThreadId) {
388         let state = &mut self.threads[thread].state;
389         assert_eq!(*state, ThreadState::BlockedOnSync);
390         *state = ThreadState::Enabled;
391     }
392
393     /// Change the active thread to some enabled thread.
394     fn yield_active_thread(&mut self) {
395         // We do not yield immediately, as swapping out the current stack while executing a MIR statement
396         // could lead to all sorts of confusion.
397         // We should only switch stacks between steps.
398         self.yield_active_thread = true;
399     }
400
401     /// Register the given `callback` to be called once the `call_time` passes.
402     ///
403     /// The callback will be called with `thread` being the active thread, and
404     /// the callback may not change the active thread.
405     fn register_timeout_callback(
406         &mut self,
407         thread: ThreadId,
408         call_time: Time,
409         callback: TimeoutCallback<'mir, 'tcx>,
410     ) {
411         self.timeout_callbacks
412             .try_insert(thread, TimeoutCallbackInfo { call_time, callback })
413             .unwrap();
414     }
415
416     /// Unregister the callback for the `thread`.
417     fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) {
418         self.timeout_callbacks.remove(&thread);
419     }
420
421     /// Get a callback that is ready to be called.
422     fn get_ready_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> {
423         // We iterate over all threads in the order of their indices because
424         // this allows us to have a deterministic scheduler.
425         for thread in self.threads.indices() {
426             match self.timeout_callbacks.entry(thread) {
427                 Entry::Occupied(entry) =>
428                     if entry.get().call_time.get_wait_time() == Duration::new(0, 0) {
429                         return Some((thread, entry.remove().callback));
430                     },
431                 Entry::Vacant(_) => {}
432             }
433         }
434         None
435     }
436
437     /// Wakes up threads joining on the active one and deallocates thread-local statics.
438     /// The `AllocId` that can now be freed are returned.
439     fn thread_terminated(
440         &mut self,
441         mut data_race: Option<&mut data_race::GlobalState>,
442     ) -> Vec<Pointer<Tag>> {
443         let mut free_tls_statics = Vec::new();
444         {
445             let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut();
446             thread_local_statics.retain(|&(_def_id, thread), &mut alloc_id| {
447                 if thread != self.active_thread {
448                     // Keep this static around.
449                     return true;
450                 }
451                 // Delete this static from the map and from memory.
452                 // We cannot free directly here as we cannot use `?` in this context.
453                 free_tls_statics.push(alloc_id);
454                 return false;
455             });
456         }
457         // Set the thread into a terminated state in the data-race detector
458         if let Some(ref mut data_race) = data_race {
459             data_race.thread_terminated();
460         }
461         // Check if we need to unblock any threads.
462         for (i, thread) in self.threads.iter_enumerated_mut() {
463             if thread.state == ThreadState::BlockedOnJoin(self.active_thread) {
464                 // The thread has terminated, mark happens-before edge to joining thread
465                 if let Some(ref mut data_race) = data_race {
466                     data_race.thread_joined(i, self.active_thread);
467                 }
468                 trace!("unblocking {:?} because {:?} terminated", i, self.active_thread);
469                 thread.state = ThreadState::Enabled;
470             }
471         }
472         return free_tls_statics;
473     }
474
475     /// Decide which action to take next and on which thread.
476     ///
477     /// The currently implemented scheduling policy is the one that is commonly
478     /// used in stateless model checkers such as Loom: run the active thread as
479     /// long as we can and switch only when we have to (the active thread was
480     /// blocked, terminated, or has explicitly asked to be preempted).
481     fn schedule(
482         &mut self,
483         data_race: &Option<data_race::GlobalState>,
484     ) -> InterpResult<'tcx, SchedulingAction> {
485         // Check whether the thread has **just** terminated (`check_terminated`
486         // checks whether the thread has popped all its stack and if yes, sets
487         // the thread state to terminated).
488         if self.threads[self.active_thread].check_terminated() {
489             return Ok(SchedulingAction::ExecuteDtors);
490         }
491         // If we get here again and the thread is *still* terminated, there are no more dtors to run.
492         if self.threads[MAIN_THREAD].state == ThreadState::Terminated {
493             // The main thread terminated; stop the program.
494             if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) {
495                 // FIXME: This check should be either configurable or just emit
496                 // a warning. For example, it seems normal for a program to
497                 // terminate without waiting for its detached threads to
498                 // terminate. However, this case is not trivial to support
499                 // because we also probably do not want to consider the memory
500                 // owned by these threads as leaked.
501                 throw_unsup_format!("the main thread terminated without waiting for other threads");
502             }
503             return Ok(SchedulingAction::Stop);
504         }
505         // This thread and the program can keep going.
506         if self.threads[self.active_thread].state == ThreadState::Enabled
507             && !self.yield_active_thread
508         {
509             // The currently active thread is still enabled, just continue with it.
510             return Ok(SchedulingAction::ExecuteStep);
511         }
512         // The active thread yielded. Let's see if there are any timeouts to take care of. We do
513         // this *before* running any other thread, to ensure that timeouts "in the past" fire before
514         // any other thread can take an action. This ensures that for `pthread_cond_timedwait`, "an
515         // error is returned if [...] the absolute time specified by abstime has already been passed
516         // at the time of the call".
517         // <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html>
518         let potential_sleep_time =
519             self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min();
520         if potential_sleep_time == Some(Duration::new(0, 0)) {
521             return Ok(SchedulingAction::ExecuteTimeoutCallback);
522         }
523         // No callbacks scheduled, pick a regular thread to execute.
524         // We need to pick a new thread for execution.
525         for (id, thread) in self.threads.iter_enumerated() {
526             if thread.state == ThreadState::Enabled {
527                 if !self.yield_active_thread || id != self.active_thread {
528                     self.active_thread = id;
529                     if let Some(data_race) = data_race {
530                         data_race.thread_set_active(self.active_thread);
531                     }
532                     break;
533                 }
534             }
535         }
536         self.yield_active_thread = false;
537         if self.threads[self.active_thread].state == ThreadState::Enabled {
538             return Ok(SchedulingAction::ExecuteStep);
539         }
540         // We have not found a thread to execute.
541         if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) {
542             unreachable!("all threads terminated without the main thread terminating?!");
543         } else if let Some(sleep_time) = potential_sleep_time {
544             // All threads are currently blocked, but we have unexecuted
545             // timeout_callbacks, which may unblock some of the threads. Hence,
546             // sleep until the first callback.
547             std::thread::sleep(sleep_time);
548             Ok(SchedulingAction::ExecuteTimeoutCallback)
549         } else {
550             throw_machine_stop!(TerminationInfo::Deadlock);
551         }
552     }
553 }
554
555 // Public interface to thread management.
556 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
557 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
558     /// Get a thread-specific allocation id for the given thread-local static.
559     /// If needed, allocate a new one.
560     fn get_or_create_thread_local_alloc(
561         &mut self,
562         def_id: DefId,
563     ) -> InterpResult<'tcx, Pointer<Tag>> {
564         let this = self.eval_context_mut();
565         let tcx = this.tcx;
566         if let Some(old_alloc) = this.machine.threads.get_thread_local_alloc_id(def_id) {
567             // We already have a thread-specific allocation id for this
568             // thread-local static.
569             Ok(old_alloc)
570         } else {
571             // We need to allocate a thread-specific allocation id for this
572             // thread-local static.
573             // First, we compute the initial value for this static.
574             if tcx.is_foreign_item(def_id) {
575                 throw_unsup_format!("foreign thread-local statics are not supported");
576             }
577             let allocation = tcx.eval_static_initializer(def_id)?;
578             // Create a fresh allocation with this content.
579             let new_alloc =
580                 this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into());
581             this.machine.threads.set_thread_local_alloc(def_id, new_alloc);
582             Ok(new_alloc)
583         }
584     }
585
586     #[inline]
587     fn create_thread(&mut self) -> ThreadId {
588         let this = self.eval_context_mut();
589         let id = this.machine.threads.create_thread();
590         if let Some(data_race) = &mut this.memory.extra.data_race {
591             data_race.thread_created(id);
592         }
593         id
594     }
595
596     #[inline]
597     fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> {
598         let this = self.eval_context_mut();
599         this.machine.threads.detach_thread(thread_id)
600     }
601
602     #[inline]
603     fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> {
604         let this = self.eval_context_mut();
605         this.machine.threads.join_thread(joined_thread_id, this.memory.extra.data_race.as_mut())?;
606         Ok(())
607     }
608
609     #[inline]
610     fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId {
611         let this = self.eval_context_mut();
612         if let Some(data_race) = &this.memory.extra.data_race {
613             data_race.thread_set_active(thread_id);
614         }
615         this.machine.threads.set_active_thread_id(thread_id)
616     }
617
618     #[inline]
619     fn get_active_thread(&self) -> ThreadId {
620         let this = self.eval_context_ref();
621         this.machine.threads.get_active_thread_id()
622     }
623
624     #[inline]
625     fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> {
626         let this = self.eval_context_mut();
627         this.machine.threads.active_thread_mut()
628     }
629
630     #[inline]
631     fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> {
632         let this = self.eval_context_ref();
633         this.machine.threads.active_thread_ref()
634     }
635
636     #[inline]
637     fn get_total_thread_count(&self) -> usize {
638         let this = self.eval_context_ref();
639         this.machine.threads.get_total_thread_count()
640     }
641
642     #[inline]
643     fn has_terminated(&self, thread_id: ThreadId) -> bool {
644         let this = self.eval_context_ref();
645         this.machine.threads.has_terminated(thread_id)
646     }
647
648     #[inline]
649     fn enable_thread(&mut self, thread_id: ThreadId) {
650         let this = self.eval_context_mut();
651         this.machine.threads.enable_thread(thread_id);
652     }
653
654     #[inline]
655     fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] {
656         let this = self.eval_context_ref();
657         this.machine.threads.active_thread_stack()
658     }
659
660     #[inline]
661     fn active_thread_stack_mut(&mut self) -> &mut Vec<Frame<'mir, 'tcx, Tag, FrameData<'tcx>>> {
662         let this = self.eval_context_mut();
663         this.machine.threads.active_thread_stack_mut()
664     }
665
666     #[inline]
667     fn set_active_thread_name(&mut self, new_thread_name: Vec<u8>) {
668         let this = self.eval_context_mut();
669         if let Some(data_race) = &mut this.memory.extra.data_race {
670             if let Ok(string) = String::from_utf8(new_thread_name.clone()) {
671                 data_race.thread_set_name(this.machine.threads.active_thread, string);
672             }
673         }
674         this.machine.threads.set_thread_name(new_thread_name);
675     }
676
677     #[inline]
678     fn get_active_thread_name<'c>(&'c self) -> &'c [u8]
679     where
680         'mir: 'c,
681     {
682         let this = self.eval_context_ref();
683         this.machine.threads.get_thread_name()
684     }
685
686     #[inline]
687     fn block_thread(&mut self, thread: ThreadId) {
688         let this = self.eval_context_mut();
689         this.machine.threads.block_thread(thread);
690     }
691
692     #[inline]
693     fn unblock_thread(&mut self, thread: ThreadId) {
694         let this = self.eval_context_mut();
695         this.machine.threads.unblock_thread(thread);
696     }
697
698     #[inline]
699     fn yield_active_thread(&mut self) {
700         let this = self.eval_context_mut();
701         this.machine.threads.yield_active_thread();
702     }
703
704     #[inline]
705     fn register_timeout_callback(
706         &mut self,
707         thread: ThreadId,
708         call_time: Time,
709         callback: TimeoutCallback<'mir, 'tcx>,
710     ) {
711         let this = self.eval_context_mut();
712         this.machine.threads.register_timeout_callback(thread, call_time, callback);
713     }
714
715     #[inline]
716     fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) {
717         let this = self.eval_context_mut();
718         this.machine.threads.unregister_timeout_callback_if_exists(thread);
719     }
720
721     /// Execute a timeout callback on the callback's thread.
722     #[inline]
723     fn run_timeout_callback(&mut self) -> InterpResult<'tcx> {
724         let this = self.eval_context_mut();
725         let (thread, callback) =
726             if let Some((thread, callback)) = this.machine.threads.get_ready_callback() {
727                 (thread, callback)
728             } else {
729                 // get_ready_callback can return None if the computer's clock
730                 // was shifted after calling the scheduler and before the call
731                 // to get_ready_callback (see issue
732                 // https://github.com/rust-lang/miri/issues/1763). In this case,
733                 // just do nothing, which effectively just returns to the
734                 // scheduler.
735                 return Ok(());
736             };
737         // This back-and-forth with `set_active_thread` is here because of two
738         // design decisions:
739         // 1. Make the caller and not the callback responsible for changing
740         //    thread.
741         // 2. Make the scheduler the only place that can change the active
742         //    thread.
743         let old_thread = this.set_active_thread(thread);
744         callback(this)?;
745         this.set_active_thread(old_thread);
746         Ok(())
747     }
748
749     /// Decide which action to take next and on which thread.
750     #[inline]
751     fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
752         let this = self.eval_context_mut();
753         let data_race = &this.memory.extra.data_race;
754         this.machine.threads.schedule(data_race)
755     }
756
757     /// Handles thread termination of the active thread: wakes up threads joining on this one,
758     /// and deallocated thread-local statics.
759     ///
760     /// This is called from `tls.rs` after handling the TLS dtors.
761     #[inline]
762     fn thread_terminated(&mut self) -> InterpResult<'tcx> {
763         let this = self.eval_context_mut();
764         for ptr in this.machine.threads.thread_terminated(this.memory.extra.data_race.as_mut()) {
765             this.memory.deallocate(ptr.into(), None, MiriMemoryKind::Tls.into())?;
766         }
767         Ok(())
768     }
769 }