- /// Unblock any one thread from the given blockset if it contains at least
- /// one. Return the id of the unblocked thread.
- fn unblock_some_thread(&mut self, set: BlockSetId) -> Option<ThreadId> {
- for (id, thread) in self.threads.iter_enumerated_mut() {
- if thread.state == ThreadState::Blocked(set) {
- trace!("unblocking {:?} in blockset {:?}", id, set);
- thread.state = ThreadState::Enabled;
- return Some(id);
+ /// Change the active thread to some enabled thread.
+ fn yield_active_thread(&mut self) {
+ // We do not yield immediately, as swapping out the current stack while executing a MIR statement
+ // could lead to all sorts of confusion.
+ // We should only switch stacks between steps.
+ self.yield_active_thread = true;
+ }
+
+ /// Register the given `callback` to be called once the `call_time` passes.
+ ///
+ /// The callback will be called with `thread` being the active thread, and
+ /// the callback may not change the active thread.
+ fn register_timeout_callback(
+ &mut self,
+ thread: ThreadId,
+ call_time: Time,
+ callback: TimeoutCallback<'mir, 'tcx>,
+ ) {
+ self.timeout_callbacks
+ .try_insert(thread, TimeoutCallbackInfo { call_time, callback })
+ .unwrap();
+ }
+
+ /// Unregister the callback for the `thread`.
+ fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) {
+ self.timeout_callbacks.remove(&thread);
+ }
+
+ /// Get a callback that is ready to be called.
+ fn get_ready_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> {
+ // We iterate over all threads in the order of their indices because
+ // this allows us to have a deterministic scheduler.
+ for thread in self.threads.indices() {
+ match self.timeout_callbacks.entry(thread) {
+ Entry::Occupied(entry) =>
+ if entry.get().call_time.get_wait_time() == Duration::new(0, 0) {
+ return Some((thread, entry.remove().callback));
+ },
+ Entry::Vacant(_) => {}