00001 // scheduler.cc 00002 // Routines to choose the next thread to run, and to dispatch to 00003 // that thread. 00004 // 00005 // These routines assume that interrupts are already disabled. 00006 // If interrupts are disabled, we can assume mutual exclusion 00007 // (since we are on a uniprocessor). 00008 // 00009 // NOTE: We can't use Locks to provide mutual exclusion here, since 00010 // if we needed to wait for a lock, and the lock was busy, we would 00011 // end up calling FindNextToRun(), and that would put us in an 00012 // infinite loop. 00013 // 00014 // Very simple implementation -- no priorities, straight FIFO. 00015 // Might need to be improved in later assignments. 00016 // 00017 // Copyright (c) 1992-1993 The Regents of the University of California. 00018 // All rights reserved. See copyright.h for copyright notice and limitation 00019 // of liability and disclaimer of warranty provisions. 00020 00021 #include "copyright.h" 00022 #include "scheduler.h" 00023 #include "system.h" 00024 00025 //---------------------------------------------------------------------- 00026 // Scheduler::Scheduler 00027 // Initialize the list of ready but not running threads to empty. 00028 //---------------------------------------------------------------------- 00029 00030 Scheduler::Scheduler() 00031 { 00032 readyList = new List; 00033 } 00034 00035 //---------------------------------------------------------------------- 00036 // Scheduler::~Scheduler 00037 // De-allocate the list of ready threads. 00038 //---------------------------------------------------------------------- 00039 00040 Scheduler::~Scheduler() 00041 { 00042 delete readyList; 00043 } 00044 00045 //---------------------------------------------------------------------- 00046 // Scheduler::ReadyToRun 00047 // Mark a thread as ready, but not running. 00048 // Put it on the ready list, for later scheduling onto the CPU. 00049 // 00050 // "thread" is the thread to be put on the ready list. 00051 //---------------------------------------------------------------------- 00052 00053 void 00054 Scheduler::ReadyToRun (Thread *thread) 00055 { 00056 DEBUG('t', "Putting thread %s on ready list.\n", thread->getName()); 00057 00058 thread->setStatus(READY); 00059 readyList->Append((void *)thread); 00060 } 00061 00062 //---------------------------------------------------------------------- 00063 // Scheduler::FindNextToRun 00064 // Return the next thread to be scheduled onto the CPU. 00065 // If there are no ready threads, return NULL. 00066 // Side effect: 00067 // Thread is removed from the ready list. 00068 //---------------------------------------------------------------------- 00069 00070 Thread * 00071 Scheduler::FindNextToRun () 00072 { 00073 return (Thread *)readyList->Remove(); 00074 } 00075 00076 //---------------------------------------------------------------------- 00077 // Scheduler::Run 00078 // Dispatch the CPU to nextThread. Save the state of the old thread, 00079 // and load the state of the new thread, by calling the machine 00080 // dependent context switch routine, SWITCH. 00081 // 00082 // Note: we assume the state of the previously running thread has 00083 // already been changed from running to blocked or ready (depending). 00084 // Side effect: 00085 // The global variable currentThread becomes nextThread. 00086 // 00087 // "nextThread" is the thread to be put into the CPU. 00088 //---------------------------------------------------------------------- 00089 00090 void 00091 Scheduler::Run (Thread *nextThread) 00092 { 00093 Thread *oldThread = currentThread; 00094 00095 #ifdef USER_PROGRAM // ignore until running user programs 00096 if (currentThread->space != NULL) { // if this thread is a user program, 00097 currentThread->SaveUserState(); // save the user's CPU registers 00098 currentThread->space->SaveState(); 00099 } 00100 #endif 00101 00102 oldThread->CheckOverflow(); // check if the old thread 00103 // had an undetected stack overflow 00104 00105 currentThread = nextThread; // switch to the next thread 00106 currentThread->setStatus(RUNNING); // nextThread is now running 00107 00108 DEBUG('t', "Switching from thread \"%s\" to thread \"%s\"\n", 00109 oldThread->getName(), nextThread->getName()); 00110 00111 // This is a machine-dependent assembly language routine defined 00112 // in switch.s. You may have to think 00113 // a bit to figure out what happens after this, both from the point 00114 // of view of the thread and from the perspective of the "outside world". 00115 00116 SWITCH(oldThread, nextThread); 00117 00118 DEBUG('t', "Now in thread \"%s\"\n", currentThread->getName()); 00119 00120 // If the old thread gave up the processor because it was finishing, 00121 // we need to delete its carcass. Note we cannot delete the thread 00122 // before now (for example, in Thread::Finish()), because up to this 00123 // point, we were still running on the old thread's stack! 00124 if (threadToBeDestroyed != NULL) { 00125 delete threadToBeDestroyed; 00126 threadToBeDestroyed = NULL; 00127 } 00128 00129 #ifdef USER_PROGRAM 00130 if (currentThread->space != NULL) { // if there is an address space 00131 currentThread->RestoreUserState(); // to restore, do it. 00132 currentThread->space->RestoreState(); 00133 } 00134 #endif 00135 } 00136 00137 //---------------------------------------------------------------------- 00138 // Scheduler::Print 00139 // Print the scheduler state -- in other words, the contents of 00140 // the ready list. For debugging. 00141 //---------------------------------------------------------------------- 00142 void 00143 Scheduler::Print() 00144 { 00145 printf("Ready list contents:\n"); 00146 readyList->Mapcar((VoidFunctionPtr) ThreadPrint); 00147 }
1.2.14 written by Dimitri van Heesch,
© 1997-2002