fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
        // Check whether the thread has **just** terminated (`check_terminated`
        // checks whether the thread has popped all its stack and if yes, sets
        // the thread state to terminated).
        if self.threads[self.active_thread].check_terminated() {
            // Check if we need to unblock any threads.
            for (i, thread) in self.threads.iter_enumerated_mut() {
                if thread.state == ThreadState::BlockedOnJoin(self.active_thread) {
                    trace!("unblocking {:?} because {:?} terminated", i, self.active_thread);
                    thread.state = ThreadState::Enabled;
                }
            }
            return Ok(SchedulingAction::ExecuteDtors);
        }
        if self.threads[MAIN_THREAD].state == ThreadState::Terminated {
            // The main thread terminated; stop the program.
            if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) {
                // FIXME: This check should be either configurable or just emit
                // a warning. For example, it seems normal for a program to
                // terminate without waiting for its detached threads to
                // terminate. However, this case is not trivial to support
                // because we also probably do not want to consider the memory
                // owned by these threads as leaked.
                throw_unsup_format!("the main thread terminated without waiting for other threads");
            }
            return Ok(SchedulingAction::Stop);
        }
        if self.threads[self.active_thread].state == ThreadState::Enabled
            && !self.yield_active_thread
        {
            // The currently active thread is still enabled, just continue with it.
            return Ok(SchedulingAction::ExecuteStep);
        }
        // We need to pick a new thread for execution.
        for (id, thread) in self.threads.iter_enumerated() {
            if thread.state == ThreadState::Enabled {
                if !self.yield_active_thread || id != self.active_thread {
                    self.active_thread = id;
                    break;
                }
            }
        }
        self.yield_active_thread = false;
        if self.threads[self.active_thread].state == ThreadState::Enabled {
            return Ok(SchedulingAction::ExecuteStep);
        }
        // We have not found a thread to execute.
        if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) {
            unreachable!();
        } else {
            throw_machine_stop!(TerminationInfo::Deadlock);
        }
    }
/// Decide which action to take next and on which thread.
///
/// The currently implemented scheduling policy is the one that is commonly
/// used in stateless model checkers such as Loom: run the active thread as
/// long as we can and switch only when we have to (the active thread was
/// blocked, terminated, or has explicitly asked to be preempted).
Decide which action to take next and on which thread.
The currently implemented scheduling policy is the one that is commonly
used in stateless model checkers such as Loom: run the active thread as
long as we can and switch only when we have to (the active thread was
blocked, terminated, or has explicitly asked to be preempted).
Decide which action to take next and on which thread . The currently implemented scheduling policy is the one that is commonly used in stateless model checkers such as Loom : run the active thread as long as we can and switch only when we have to ( the active thread was blocked terminated or has explicitly asked to be preempted ) .
fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
        // Check whether the thread has **just** terminated (`check_terminated`
        // checks whether the thread has popped all its stack and if yes, sets
        // the thread state to terminated).
        if self.threads[self.active_thread].check_terminated() {
            // Check if we need to unblock any threads.
            for (i, thread) in self.threads.iter_enumerated_mut() {
                if thread.state == ThreadState::BlockedOnJoin(self.active_thread) {
                    trace!("unblocking {:?} because {:?} terminated", i, self.active_thread);
                    thread.state = ThreadState::Enabled;
                }
            }
            return Ok(SchedulingAction::ExecuteDtors);
        }
        if self.threads[MAIN_THREAD].state == ThreadState::Terminated {
            // The main thread terminated; stop the program.
            if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) {
                // FIXME: This check should be either configurable or just emit
                // a warning. For example, it seems normal for a program to
                // terminate without waiting for its detached threads to
                // terminate. However, this case is not trivial to support
                // because we also probably do not want to consider the memory
                // owned by these threads as leaked.
                throw_unsup_format!("the main thread terminated without waiting for other threads");
            }
            return Ok(SchedulingAction::Stop);
        }
        if self.threads[self.active_thread].state == ThreadState::Enabled
            && !self.yield_active_thread
        {
            // The currently active thread is still enabled, just continue with it.
            return Ok(SchedulingAction::ExecuteStep);
        }
        // We need to pick a new thread for execution.
        for (id, thread) in self.threads.iter_enumerated() {
            if thread.state == ThreadState::Enabled {
                if !self.yield_active_thread || id != self.active_thread {
                    self.active_thread = id;
                    break;
                }
            }
        }
        self.yield_active_thread = false;
        if self.threads[self.active_thread].state == ThreadState::Enabled {
            return Ok(SchedulingAction::ExecuteStep);
        }
        // We have not found a thread to execute.
        if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) {
            unreachable!();
        } else {
            throw_machine_stop!(TerminationInfo::Deadlock);
        }
    }
fn schedule ( & mut self ) -> InterpResult < ' tcx , SchedulingAction > { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). if self . threads [ self . active_thread ] . check_terminated ( ) { // Check if we need to unblock any threads. for ( i , thread ) in self . threads . iter_enumerated_mut ( ) { if thread . state == ThreadState :: BlockedOnJoin ( self . active_thread ) { trace ! ( " " i self active_thread ) ; thread . state = ThreadState :: Enabled ; } } return Ok ( SchedulingAction :: ExecuteDtors ) ; } if self . threads [ MAIN_THREAD ] . state == ThreadState :: Terminated { // The main thread terminated; stop the program. if self . threads . iter ( ) . any ( | thread | thread . state != ThreadState :: Terminated ) { // FIXME: This check should be either configurable or just emit // a warning. For example, it seems normal for a program to // terminate without waiting for its detached threads to // terminate. However, this case is not trivial to support // because we also probably do not want to consider the memory // owned by these threads as leaked. throw_unsup_format ! ( " " ) ; } return Ok ( SchedulingAction :: Stop ) ; } if self . threads [ self . active_thread ] . state == ThreadState :: Enabled && ! self . yield_active_thread { // The currently active thread is still enabled, just continue with it. return Ok ( SchedulingAction :: ExecuteStep ) ; } // We need to pick a new thread for execution. for ( id , thread ) in self . threads . iter_enumerated ( ) { if thread . state == ThreadState :: Enabled { if ! self . yield_active_thread || id != self . active_thread { self . active_thread = id ; break ; } } } self . yield_active_thread = false ; if self . threads [ self . active_thread ] . state == ThreadState :: Enabled { return Ok ( SchedulingAction :: ExecuteStep ) ; } // We have not found a thread to execute. if self . threads . iter ( ) . all ( | thread | thread . state == ThreadState :: Terminated ) { unreachable ! ( ) ; } else { throw_machine_stop ! ( TerminationInfo Deadlock ) ; } }
Decide which action to take next and on which thread.
Decide which action to take next and on which thread .
&mut self
&mut self