📄 scheduler.cc
字号:
// scheduler.cc // Routines to choose the next thread to run, and to dispatch to// that thread.//// These routines assume that interrupts are already disabled.// If interrupts are disabled, we can assume mutual exclusion// (since we are on a uniprocessor).//// NOTE: We can't use Locks to provide mutual exclusion here, since// if we needed to wait for a lock, and the lock was busy, we would // end up calling FindNextToRun(), and that would put us in an // infinite loop.//// Very simple implementation -- no priorities, straight FIFO.// Might need to be improved in later assignments.//// Copyright (c) 1992-1996 The Regents of the University of California.// All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions.#include "copyright.h"#include "debug.h"#include "scheduler.h"#include "main.h"//----------------------------------------------------------------------// Scheduler::Scheduler// Initialize the list of ready but not running threads.// Initially, no ready threads.//----------------------------------------------------------------------Scheduler::Scheduler(){ readyList = new List<Thread *>; toBeDestroyed = NULL;} //----------------------------------------------------------------------// Scheduler::~Scheduler// De-allocate the list of ready threads.//----------------------------------------------------------------------Scheduler::~Scheduler(){ delete readyList; } //----------------------------------------------------------------------// Scheduler::ReadyToRun// Mark a thread as ready, but not running.// Put it on the ready list, for later scheduling onto the CPU.//// "thread" is the thread to be put on the ready list.//----------------------------------------------------------------------voidScheduler::ReadyToRun (Thread *thread){ ASSERT(kernel->interrupt->getLevel() == IntOff); DEBUG(dbgThread, "Putting thread on ready list: " << thread->getName()); thread->setStatus(READY); readyList->Append(thread);}//----------------------------------------------------------------------// Scheduler::FindNextToRun// Return the next thread to be scheduled onto the CPU.// If there are no ready threads, return NULL.// Side effect:// Thread is removed from the ready list.//----------------------------------------------------------------------Thread *Scheduler::FindNextToRun (){ ASSERT(kernel->interrupt->getLevel() == IntOff); if (readyList->IsEmpty()) { return NULL; } else { return readyList->RemoveFront(); }}//----------------------------------------------------------------------// Scheduler::Run// Dispatch the CPU to nextThread. Save the state of the old thread,// and load the state of the new thread, by calling the machine// dependent context switch routine, SWITCH.//// Note: we assume the state of the previously running thread has// already been changed from running to blocked or ready (depending).// Side effect:// The global variable kernel->currentThread becomes nextThread.//// "nextThread" is the thread to be put into the CPU.// "finishing" is set if the current thread is to be deleted// once we're no longer running on its stack// (when the next thread starts running)//----------------------------------------------------------------------voidScheduler::Run (Thread *nextThread, bool finishing){ Thread *oldThread = kernel->currentThread; ASSERT(kernel->interrupt->getLevel() == IntOff); if (finishing) { // mark that we need to delete current thread ASSERT(toBeDestroyed == NULL); toBeDestroyed = oldThread; } if (oldThread->space != NULL) { // if this thread is a user program, oldThread->SaveUserState(); // save the user's CPU registers oldThread->space->SaveState(); } oldThread->CheckOverflow(); // check if the old thread // had an undetected stack overflow kernel->currentThread = nextThread; // switch to the next thread nextThread->setStatus(RUNNING); // nextThread is now running DEBUG(dbgThread, "Switching from: " << oldThread->getName() << " to: " << nextThread->getName()); // This is a machine-dependent assembly language routine defined // in switch.s. You may have to think // a bit to figure out what happens after this, both from the point // of view of the thread and from the perspective of the "outside world". SWITCH(oldThread, nextThread); // we're back, running oldThread // interrupts are off when we return from switch! ASSERT(kernel->interrupt->getLevel() == IntOff); DEBUG(dbgThread, "Now in thread: " << oldThread->getName()); CheckToBeDestroyed(); // check if thread we were running // before this one has finished // and needs to be cleaned up if (oldThread->space != NULL) { // if there is an address space oldThread->RestoreUserState(); // to restore, do it. oldThread->space->RestoreState(); }}//----------------------------------------------------------------------// Scheduler::CheckToBeDestroyed// If the old thread gave up the processor because it was finishing,// we need to delete its carcass. Note we cannot delete the thread// before now (for example, in Thread::Finish()), because up to this// point, we were still running on the old thread's stack!//----------------------------------------------------------------------voidScheduler::CheckToBeDestroyed(){ if (toBeDestroyed != NULL) { delete toBeDestroyed; toBeDestroyed = NULL; }} //----------------------------------------------------------------------// Scheduler::Print// Print the scheduler state -- in other words, the contents of// the ready list. For debugging.//----------------------------------------------------------------------voidScheduler::Print(){ cout << "Ready list contents:\n"; readyList->Apply(ThreadPrint);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -