📄 scheduler.cpp
字号:
// 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-1993 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 "scheduler.h"#include "system.h"#include <stdio.h>// this is a function prototype for the actual interrupt handlervoid SchedInterruptHandler(int dummy);//----------------------------------------------------------------------// Scheduler::Scheduler// Initialize the list of ready but not running threads to empty.//----------------------------------------------------------------------Scheduler::Scheduler(){ readyList = new List<Thread *>(); suspendedList = new List<Thread *>(); ptimer = 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){ DEBUG('t', "Putting thread %s on ready list.\n", thread->getName()); thread->setStatus(READY); // MP1 - don't forget the usefulness of the break statement switch (policy) { case SCHED_PRIO: readyList->SortedInsert(thread,thread->MAX_PRIORITY-thread->getPriority());break;// Priority case SCHED_MQ: readyList->SortedInsert(thread,thread->MAX_PRIORITY-thread->getPriority());break; // Multiple Queues case SCHED_SJF: readyList->SortedInsert(thread,thread->getTimeLeft());break; // Shortest Job First case SCHED_SRTN: readyList->SortedInsert(thread,thread->getTimeLeft());break;// Shortest Remaining Time Next case SCHED_FCFS: // First Come First Served (FCFS) scheduling // FCFS is the NachOS default case SCHED_RR: readyList->Append(thread);break;// Round Robin scheduling default: readyList->Append(thread); break; }}//----------------------------------------------------------------------// Scheduler::FindNextToRun//----------------------------------------------------------------------Thread *Scheduler::FindNextToRun (){ // MP1 return(readyList->Remove());}//----------------------------------------------------------------------// Scheduler::ShouldISwitch// This function uses the policy information to tell a thread::fork// to preempt the current thread or to not. The answer is the domain of// the scheduler, so it is a member function call.//----------------------------------------------------------------------bool Scheduler::ShouldISwitch (Thread * oldThread, Thread * newThread){ bool answer; // MP1 - don't forget the break statements switch( policy ) { case SCHED_FCFS: // First-come first-served scheduling case SCHED_MQ: if((oldThread->getPriority())>=(newThread->getPriority()))answer = false;
else answer = true;break;
// Multiple Queues case SCHED_RR: break; // Round Robin scheduling case SCHED_PRIO: if (oldThread->getPriority() < newThread->getPriority()) answer = true ; break; // Priority scheduling case SCHED_SRTN: if (oldThread->getTimeLeft() >newThread->getTimeLeft()) answer = true ; break; // Shortest Remaining Time Next case SCHED_SJF: answer=false; break;// Shortest Job First default: answer = false; break; } return answer;}//----------------------------------------------------------------------// 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 currentThread becomes nextThread.//// "nextThread" is the thread to be put into the CPU.//----------------------------------------------------------------------voidScheduler::Run (Thread *nextThread){ Thread *oldThread = currentThread; #ifdef USER_PROGRAM // ignore until running user programs if (currentThread->space != NULL) { // if this thread is a user program, currentThread->SaveUserState(); // save the user's CPU registers currentThread->space->SaveState(); }#endif oldThread->CheckOverflow(); // check if the old thread // had an undetected stack overflow currentThread = nextThread; // switch to the next thread currentThread->setStatus(RUNNING); // nextThread is now running // MP1 - put any processing before the SWITCH() statement DEBUG('t', "Switching from thread \"%s\" to thread \"%s\"\n", oldThread->getName(), 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". //RRif(policy==SCHED_RR&¤tThread->getTimeLeft()>=3&&!readyList->IsEmpty())
interrupt->Schedule(SchedInterruptHandler, (int) this, 40, TimerInt);
SWITCH(oldThread, nextThread); DEBUG('t', "Now in thread \"%s\"\n", currentThread->getName()); // 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! if (threadToBeDestroyed != NULL) { delete threadToBeDestroyed; threadToBeDestroyed = NULL; } #ifdef USER_PROGRAM if (currentThread->space != NULL) { // if there is an address space currentThread->RestoreUserState(); // to restore, do it. currentThread->space->RestoreState(); }#endif}//---------------------------------------------------------------------// Suspends a thread from execution. The suspended thread is removed// from ready list and added to suspended list. The suspended thread // remains there until it is resumed by some other thread. Note that// it is not an error to suspend an thread which is already in the // suspended state.//// NOTE: This method assumes that interrupts have been turned off.//---------------------------------------------------------------------void Scheduler::Suspend(Thread *thread) { List<Thread *> *tmp = new List<Thread *>(); Thread *t; // Remove the thread from ready list. while (!readyList->IsEmpty()) { t = readyList->Remove(); if (t == thread) break; else tmp->Prepend(t); } // Add the suspended thread to the suspended list if (t == thread) { t->setStatus(SUSPENDED); suspendedList->Append(t); } // Now all threads before the suspended thread in the ready list // are in the suspended list. Add them back to the ready list. while (!tmp->IsEmpty()) { t = tmp->Remove(); readyList->Prepend(t); }}//---------------------------------------------------------------------// Resumes execution of a suspended thread. The thread is removed// from suspended list and added to ready list. Note that it is not an// error to resume a thread which has not been suspended.//// NOTE: This method assumes that interrupts have been turned off.//---------------------------------------------------------------------void Scheduler::Resume(Thread *thread) { List<Thread *> *tmp = new List<Thread *>(); Thread *t; // Remove the thread from suspended list. while (!suspendedList->IsEmpty()) { t = suspendedList->Remove(); if (t == thread) break; else tmp->Prepend(t); } // Add the resumed thread to the ready list if (t == thread) { t->setStatus(READY); readyList->Append(t); } // Now all threads before the suspended thread in the ready list // are in the suspended list. Add them back to the ready list. while (!tmp->IsEmpty()) { t = tmp->Remove(); suspendedList->Prepend(t); }}//----------------------------------------------------------------------// Scheduler::Print// Print the scheduler state -- in other words, the contents of// the ready list. For debugging.//----------------------------------------------------------------------voidScheduler::Print(){ printf("Ready list contents:\n"); readyList->Mapcar((VoidFunctionPtr) ThreadPrint);}//----------------------------------------------------------------------// Scheduler::InterruptHandler// Handles timer interrupts for the Round Robin scheduling algorithm. // Since this is called while the system is an interrupt handler, // use YieldOnReturn.//----------------------------------------------------------------------voidScheduler::InterruptHandler( int dummy ){ // MP1 -- // dont switch out the "main" task if (strcmp(currentThread->getName(), "main")) {//RR if (interrupt->getStatus() != IdleMode)
interrupt->YieldOnReturn();// MP1 - this runs if the name of the current thread is not main // if there is only one thread left to run don't stop it }}// THUNKvoid SchedInterruptHandler( int dummy ){ scheduler->InterruptHandler( dummy );}//----------------------------------------------------------------------// Scheduler::SetSchedPolicy// Set the scheduling policy to one of SCHED_FCFS, SCHED_SJF,// SCHED_MQ, SCHED_PRIO, SCHED_MQ or SCHED_RR //----------------------------------------------------------------------void Scheduler::SetSchedPolicy(SchedPolicy pol){ SchedPolicy oldPolicy = policy; policy = pol; if( oldPolicy == policy ) return; // No change! switch (policy) { case SCHED_SJF: //printf("Shortest Job First (SJF) scheduling\n"); break; case SCHED_SRTN: printf("Shortest Remaining Time Next (SRTN) scheduling\n"); break; case SCHED_PRIO: printf("Priority scheduling\n"); break; case SCHED_MQ: printf("Multiple Queues scheduling\n"); break; case SCHED_RR: printf("Round robin scheduling\n"); break; case SCHED_FCFS: default: printf("First-Come First-Served (FCFS) scheduling\n"); break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -