00001 // thread.cc 00002 // Routines to manage threads. There are four main operations: 00003 // 00004 // Fork -- create a thread to run a procedure concurrently 00005 // with the caller (this is done in two steps -- first 00006 // allocate the Thread object, then call Fork on it) 00007 // Finish -- called when the forked procedure finishes, to clean up 00008 // Yield -- relinquish control over the CPU to another ready thread 00009 // Sleep -- relinquish control over the CPU, but thread is now blocked. 00010 // In other words, it will not run again, until explicitly 00011 // put back on the ready queue. 00012 // 00013 // Copyright (c) 1992-1993 The Regents of the University of California. 00014 // All rights reserved. See copyright.h for copyright notice and limitation 00015 // of liability and disclaimer of warranty provisions. 00016 00017 #include "copyright.h" 00018 #include "thread.h" 00019 #include "switch.h" 00020 #include "synch.h" 00021 #include "system.h" 00022 00023 #define STACK_FENCEPOST 0xdeadbeef // this is put at the top of the 00024 // execution stack, for detecting 00025 // stack overflows 00026 00027 //---------------------------------------------------------------------- 00028 // Thread::Thread 00029 // Initialize a thread control block, so that we can then call 00030 // Thread::Fork. 00031 // 00032 // "threadName" is an arbitrary string, useful for debugging. 00033 //---------------------------------------------------------------------- 00034 00035 Thread::Thread(char* threadName) 00036 { 00037 name = threadName; 00038 stackTop = NULL; 00039 stack = NULL; 00040 status = JUST_CREATED; 00041 #ifdef USER_PROGRAM 00042 space = NULL; 00043 #endif 00044 } 00045 00046 //---------------------------------------------------------------------- 00047 // Thread::~Thread 00048 // De-allocate a thread. 00049 // 00050 // NOTE: the current thread *cannot* delete itself directly, 00051 // since it is still running on the stack that we need to delete. 00052 // 00053 // NOTE: if this is the main thread, we can't delete the stack 00054 // because we didn't allocate it -- we got it automatically 00055 // as part of starting up Nachos. 00056 //---------------------------------------------------------------------- 00057 00058 Thread::~Thread() 00059 { 00060 DEBUG('t', "Deleting thread \"%s\"\n", name); 00061 00062 ASSERT(this != currentThread); 00063 if (stack != NULL) 00064 DeallocBoundedArray((char *) stack, StackSize * sizeof(int)); 00065 } 00066 00067 //---------------------------------------------------------------------- 00068 // Thread::Fork 00069 // Invoke (*func)(arg), allowing caller and callee to execute 00070 // concurrently. 00071 // 00072 // NOTE: although our definition allows only a single integer argument 00073 // to be passed to the procedure, it is possible to pass multiple 00074 // arguments by making them fields of a structure, and passing a pointer 00075 // to the structure as "arg". 00076 // 00077 // Implemented as the following steps: 00078 // 1. Allocate a stack 00079 // 2. Initialize the stack so that a call to SWITCH will 00080 // cause it to run the procedure 00081 // 3. Put the thread on the ready queue 00082 // 00083 // "func" is the procedure to run concurrently. 00084 // "arg" is a single argument to be passed to the procedure. 00085 //---------------------------------------------------------------------- 00086 00087 void 00088 Thread::Fork(VoidFunctionPtr func, int arg) 00089 { 00090 DEBUG('t', "Forking thread \"%s\" with func = 0x%x, arg = %d\n", 00091 name, (int) func, arg); 00092 00093 StackAllocate(func, arg); 00094 00095 IntStatus oldLevel = interrupt->SetLevel(IntOff); 00096 scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts 00097 // are disabled! 00098 (void) interrupt->SetLevel(oldLevel); 00099 } 00100 00101 //---------------------------------------------------------------------- 00102 // Thread::CheckOverflow 00103 // Check a thread's stack to see if it has overrun the space 00104 // that has been allocated for it. If we had a smarter compiler, 00105 // we wouldn't need to worry about this, but we don't. 00106 // 00107 // NOTE: Nachos will not catch all stack overflow conditions. 00108 // In other words, your program may still crash because of an overflow. 00109 // 00110 // If you get bizarre results (such as seg faults where there is no code) 00111 // then you *may* need to increase the stack size. You can avoid stack 00112 // overflows by not putting large data structures on the stack. 00113 // Don't do this: void foo() { int bigArray[10000]; ... } 00114 //---------------------------------------------------------------------- 00115 00116 void 00117 Thread::CheckOverflow() 00118 { 00119 if (stack != NULL) 00120 #ifdef HOST_SNAKE // Stacks grow upward on the Snakes 00121 ASSERT(stack[StackSize - 1] == STACK_FENCEPOST); 00122 #else 00123 ASSERT(*stack == (int) STACK_FENCEPOST); 00124 #endif 00125 } 00126 00127 //---------------------------------------------------------------------- 00128 // Thread::Finish 00129 // Called by ThreadRoot when a thread is done executing the 00130 // forked procedure. 00131 // 00132 // NOTE: we don't immediately de-allocate the thread data structure 00133 // or the execution stack, because we're still running in the thread 00134 // and we're still on the stack! Instead, we set "threadToBeDestroyed", 00135 // so that Scheduler::Run() will call the destructor, once we're 00136 // running in the context of a different thread. 00137 // 00138 // NOTE: we disable interrupts, so that we don't get a time slice 00139 // between setting threadToBeDestroyed, and going to sleep. 00140 //---------------------------------------------------------------------- 00141 00142 // 00143 void 00144 Thread::Finish () 00145 { 00146 (void) interrupt->SetLevel(IntOff); 00147 ASSERT(this == currentThread); 00148 00149 DEBUG('t', "Finishing thread \"%s\"\n", getName()); 00150 00151 threadToBeDestroyed = currentThread; 00152 Sleep(); // invokes SWITCH 00153 // not reached 00154 } 00155 00156 //---------------------------------------------------------------------- 00157 // Thread::Yield 00158 // Relinquish the CPU if any other thread is ready to run. 00159 // If so, put the thread on the end of the ready list, so that 00160 // it will eventually be re-scheduled. 00161 // 00162 // NOTE: returns immediately if no other thread on the ready queue. 00163 // Otherwise returns when the thread eventually works its way 00164 // to the front of the ready list and gets re-scheduled. 00165 // 00166 // NOTE: we disable interrupts, so that looking at the thread 00167 // on the front of the ready list, and switching to it, can be done 00168 // atomically. On return, we re-set the interrupt level to its 00169 // original state, in case we are called with interrupts disabled. 00170 // 00171 // Similar to Thread::Sleep(), but a little different. 00172 //---------------------------------------------------------------------- 00173 00174 void 00175 Thread::Yield () 00176 { 00177 Thread *nextThread; 00178 IntStatus oldLevel = interrupt->SetLevel(IntOff); 00179 00180 ASSERT(this == currentThread); 00181 00182 DEBUG('t', "Yielding thread \"%s\"\n", getName()); 00183 00184 nextThread = scheduler->FindNextToRun(); 00185 if (nextThread != NULL) { 00186 scheduler->ReadyToRun(this); 00187 scheduler->Run(nextThread); 00188 } 00189 (void) interrupt->SetLevel(oldLevel); 00190 } 00191 00192 //---------------------------------------------------------------------- 00193 // Thread::Sleep 00194 // Relinquish the CPU, because the current thread is blocked 00195 // waiting on a synchronization variable (Semaphore, Lock, or Condition). 00196 // Eventually, some thread will wake this thread up, and put it 00197 // back on the ready queue, so that it can be re-scheduled. 00198 // 00199 // NOTE: if there are no threads on the ready queue, that means 00200 // we have no thread to run. "Interrupt::Idle" is called 00201 // to signify that we should idle the CPU until the next I/O interrupt 00202 // occurs (the only thing that could cause a thread to become 00203 // ready to run). 00204 // 00205 // NOTE: we assume interrupts are already disabled, because it 00206 // is called from the synchronization routines which must 00207 // disable interrupts for atomicity. We need interrupts off 00208 // so that there can't be a time slice between pulling the first thread 00209 // off the ready list, and switching to it. 00210 //---------------------------------------------------------------------- 00211 void 00212 Thread::Sleep () 00213 { 00214 Thread *nextThread; 00215 00216 ASSERT(this == currentThread); 00217 ASSERT(interrupt->getLevel() == IntOff); 00218 00219 DEBUG('t', "Sleeping thread \"%s\"\n", getName()); 00220 00221 status = BLOCKED; 00222 while ((nextThread = scheduler->FindNextToRun()) == NULL) 00223 interrupt->Idle(); // no one to run, wait for an interrupt 00224 00225 scheduler->Run(nextThread); // returns when we've been signalled 00226 } 00227 00228 //---------------------------------------------------------------------- 00229 // ThreadFinish, InterruptEnable, ThreadPrint 00230 // Dummy functions because C++ does not allow a pointer to a member 00231 // function. So in order to do this, we create a dummy C function 00232 // (which we can pass a pointer to), that then simply calls the 00233 // member function. 00234 //---------------------------------------------------------------------- 00235 00236 static void ThreadFinish() { currentThread->Finish(); } 00237 static void InterruptEnable() { interrupt->Enable(); } 00238 void ThreadPrint(int arg){ Thread *t = (Thread *)arg; t->Print(); } 00239 00240 //---------------------------------------------------------------------- 00241 // Thread::StackAllocate 00242 // Allocate and initialize an execution stack. The stack is 00243 // initialized with an initial stack frame for ThreadRoot, which: 00244 // enables interrupts 00245 // calls (*func)(arg) 00246 // calls Thread::Finish 00247 // 00248 // "func" is the procedure to be forked 00249 // "arg" is the parameter to be passed to the procedure 00250 //---------------------------------------------------------------------- 00251 00252 void 00253 Thread::StackAllocate (VoidFunctionPtr func, int arg) 00254 { 00255 stack = (int *) AllocBoundedArray(StackSize * sizeof(int)); 00256 00257 #ifdef HOST_SNAKE 00258 // HP stack works from low addresses to high addresses 00259 stackTop = stack + 16; // HP requires 64-byte frame marker 00260 stack[StackSize - 1] = STACK_FENCEPOST; 00261 #else 00262 // i386 & MIPS & SPARC stack works from high addresses to low addresses 00263 #ifdef HOST_SPARC 00264 // SPARC stack must contains at least 1 activation record to start with. 00265 stackTop = stack + StackSize - 96; 00266 #else // HOST_MIPS || HOST_i386 00267 stackTop = stack + StackSize - 4; // -4 to be on the safe side! 00268 #ifdef HOST_i386 00269 // the 80386 passes the return address on the stack. In order for 00270 // SWITCH() to go to ThreadRoot when we switch to this thread, the 00271 // return addres used in SWITCH() must be the starting address of 00272 // ThreadRoot. 00273 *(--stackTop) = (int)ThreadRoot; 00274 #endif 00275 #endif // HOST_SPARC 00276 *stack = STACK_FENCEPOST; 00277 #endif // HOST_SNAKE 00278 00279 machineState[PCState] = (int) ThreadRoot; 00280 machineState[StartupPCState] = (int) InterruptEnable; 00281 machineState[InitialPCState] = (int) func; 00282 machineState[InitialArgState] = arg; 00283 machineState[WhenDonePCState] = (int) ThreadFinish; 00284 } 00285 00286 #ifdef USER_PROGRAM 00287 #include "machine.h" 00288 00289 //---------------------------------------------------------------------- 00290 // Thread::SaveUserState 00291 // Save the CPU state of a user program on a context switch. 00292 // 00293 // Note that a user program thread has *two* sets of CPU registers -- 00294 // one for its state while executing user code, one for its state 00295 // while executing kernel code. This routine saves the former. 00296 //---------------------------------------------------------------------- 00297 00298 void 00299 Thread::SaveUserState() 00300 { 00301 for (int i = 0; i < NumTotalRegs; i++) 00302 userRegisters[i] = machine->ReadRegister(i); 00303 } 00304 00305 //---------------------------------------------------------------------- 00306 // Thread::RestoreUserState 00307 // Restore the CPU state of a user program on a context switch. 00308 // 00309 // Note that a user program thread has *two* sets of CPU registers -- 00310 // one for its state while executing user code, one for its state 00311 // while executing kernel code. This routine restores the former. 00312 //---------------------------------------------------------------------- 00313 00314 void 00315 Thread::RestoreUserState() 00316 { 00317 for (int i = 0; i < NumTotalRegs; i++) 00318 machine->WriteRegister(i, userRegisters[i]); 00319 } 00320 #endif
1.2.14 written by Dimitri van Heesch,
© 1997-2002