📄 thread.cc
字号:
// thread.cc // Routines to manage threads. There are four main operations://// Fork -- create a thread to run a procedure concurrently// with the caller (this is done in two steps -- first// allocate the Thread object, then call Fork on it)// Finish -- called when the forked procedure finishes, to clean up// Yield -- relinquish control over the CPU to another ready thread// Sleep -- relinquish control over the CPU, but thread is now blocked.// In other words, it will not run again, until explicitly // put back on the ready queue.//// 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 "thread.h"#include "switch.h"#include "synch.h"#include "system.h"#define STACK_FENCEPOST 0xdeadbeef // this is put at the top of the // execution stack, for detecting // stack overflows//----------------------------------------------------------------------// Thread::Thread// Initialize a thread control block, so that we can then call// Thread::Fork.//// "threadName" is an arbitrary string, useful for debugging.//----------------------------------------------------------------------Thread::Thread(char* threadName, int prior){ name = new char[strlen(threadName)]; strcpy( name, threadName ); if (currentThread == NULL) priority = NORM_PRIORITY; else if ( prior == -1 ) priority = currentThread->getPriority(); else priority = prior; interrupted = false; joinList = new List<Thread *>(); stackTop = NULL; stack = NULL; status = JUST_CREATED;#ifdef USER_PROGRAM space = NULL;#endif}//----------------------------------------------------------------------// Thread::~Thread// De-allocate a thread.//// NOTE: the current thread *cannot* delete itself directly,// since it is still running on the stack that we need to delete.//// NOTE: if this is the main thread, we can't delete the stack// because we didn't allocate it -- we got it automatically// as part of starting up Nachos.//----------------------------------------------------------------------Thread::~Thread(){ DEBUG('t', "Deleting thread \"%s\"\n", name); ASSERT(this != currentThread); if (stack != NULL) DeallocBoundedArray((char *) stack, StackSize * sizeof(int));}//----------------------------------------------------------------------// Thread::setPriority// Sets thread priority. Note that this method causes a context switch// if the thread is in the ready queue and the new priority of the thread // is the highest in the ready queue. Note that the thread (whose priority// is being set) need not be in the ready queue. It might just have been// created, might be blocked, suspended etc.//----------------------------------------------------------------------void Thread::setPriority(int prior) { ASSERT( false );} //----------------------------------------------------------------------// NEW// Interrupts this thread. //----------------------------------------------------------------------void Thread::Interrupt() { interrupted = true;}//----------------------------------------------------------------------// NEW// Tests if the current thread has been interrupted. //----------------------------------------------------------------------bool Thread::Interrupted() { bool result = interrupted; interrupted = false; return result;}//----------------------------------------------------------------------// CHANGED// Thread::Fork// Invoke (*func)(arg), allowing caller and callee to execute // concurrently.//// NOTE: although our definition allows only a single integer argument// to be passed to the procedure, it is possible to pass multiple// arguments by making them fields of a structure, and passing a pointer// to the structure as "arg".//// Implemented as the following steps:// 1. Allocate a stack// 2. Initialize the stack so that a call to SWITCH will// cause it to run the procedure// 3. Put the thread on the ready queue// // "func" is the procedure to run concurrently.// "arg" is a single argument to be passed to the procedure.//// NOTE: This method may result in a context switch. //----------------------------------------------------------------------void Thread::Fork(VoidFunctionPtr func, int arg){ DEBUG('t', "Forking thread \"%s\" with func = 0x%x, arg = %d\n", name, (int) func, arg); StackAllocate(func, arg); IntStatus oldLevel = interrupt->SetLevel(IntOff); if ( scheduler->ShouldISwitch(currentThread, this) ) { if( interrupt->IsInHandler() ) { scheduler->ReadyToRun(this); interrupt->YieldOnReturn(); } else { scheduler->ReadyToRun(currentThread); scheduler->Run(this); } } else scheduler->ReadyToRun(this); (void) interrupt->SetLevel(oldLevel);} //------------------------------------------------------------------------// NEW// NOTE: Only other threads may do a join on this thread.////------------------------------------------------------------------------voidThread::Join(){ Thread *nextThread; ASSERT (this != currentThread); IntStatus oldLevel = interrupt->SetLevel(IntOff); currentThread->setStatus(BLOCKED); joinList->Append(currentThread); while ((nextThread = scheduler->FindNextToRun()) == NULL) interrupt->Idle(); // No thread to run, wait for an interrupt, // the only way to enabled threads to execute scheduler->Run(nextThread); (void) interrupt->SetLevel(oldLevel);}//------------------------------------------------------------------------// Thread::Suspend()// //------------------------------------------------------------------------void Thread::Suspend() { IntStatus oldLevel = interrupt->SetLevel(IntOff); printf("Student's suspend routine called\n"); // ASSERT(this != currentThread); DEBUG('t', "Thread \"%s\" suspending thread \"%s\"\n", currentThread->getName(), getName()); // Inform the scheduler which maintains the ready and suspended // list of threads to suspend the thread. scheduler->Suspend(this); (void) interrupt->SetLevel(oldLevel);} //------------------------------------------------------------------------// NEW// NOTE: Only other threads may suspend this thread.////------------------------------------------------------------------------void Thread::Resume() { IntStatus oldLevel = interrupt->SetLevel(IntOff); ASSERT(this != currentThread); DEBUG('t', "Thread \"%s\" resuming thread \"%s\"\n", currentThread->getName(), getName()); // Inform the scheduler which maintains the ready and suspended // list of threads to suspend the thread. scheduler->Resume(this); (void) interrupt->SetLevel(oldLevel); }//----------------------------------------------------------------------// Thread::CheckOverflow// Check a thread's stack to see if it has overrun the space// that has been allocated for it. If we had a smarter compiler,// we wouldn't need to worry about this, but we don't.//// NOTE: Nachos will not catch all stack overflow conditions.// In other words, your program may still crash because of an overflow.//// If you get bizarre results (such as seg faults where there is no code)// then you *may* need to increase the stack size. You can avoid stack
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -