⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thread.cc

📁 Nachos 线程
💻 CC
📖 第 1 页 / 共 2 页
字号:
// 	overflows by not putting large data structures on the stack.// 	Don't do this: void foo() { int bigArray[10000]; ... }//----------------------------------------------------------------------voidThread::CheckOverflow(){    if (stack != NULL)#ifdef HOST_SNAKE			// Stacks grow upward on the Snakes	ASSERT(stack[StackSize - 1] == STACK_FENCEPOST);#else	ASSERT(*stack == STACK_FENCEPOST);#endif}//----------------------------------------------------------------------// CHANGED// Thread::Finish// 	Called by ThreadRoot when a thread is done executing the //	forked procedure.//// 	NOTE: we don't immediately de-allocate the thread data structure //	or the execution stack, because we're still running in the thread //	and we're still on the stack!  Instead, we set "threadToBeDestroyed", //	so that Scheduler::Run() will call the destructor, once we're//	running in the context of a different thread.//// 	NOTE: we disable interrupts, so that we don't get a time slice //	between setting threadToBeDestroyed, and going to sleep.//----------------------------------------------------------------------//voidThread::Finish (){    (void) interrupt->SetLevel(IntOff);		    ASSERT(this == currentThread);        DEBUG('t', "Finishing thread \"%s\"\n", getName());        // Return all the threads that executed a join on this    // back to the READY LIST.    if (joinList)    {      Thread *joinThread;      while ( (joinThread = joinList->Remove()) )      {        joinThread->setStatus(READY);        scheduler->ReadyToRun(joinThread);      }    }      threadToBeDestroyed = currentThread;    Sleep();					// invokes SWITCH    // not reached}//----------------------------------------------------------------------// Thread::Yield// 	Relinquish the CPU if any other thread is ready to run.//	If so, put the thread on the end of the ready list, so that//	it will eventually be re-scheduled.////	NOTE: returns immediately if no other thread on the ready queue.//	Otherwise returns when the thread eventually works its way//	to the front of the ready list and gets re-scheduled.////	NOTE: we disable interrupts, so that looking at the thread//	on the front of the ready list, and switching to it, can be done//	atomically.  On return, we re-set the interrupt level to its//	original state, in case we are called with interrupts disabled. //// 	Similar to Thread::Sleep(), but a little different.//      //      NOTE: This method falsifies the invariant that the priorities//      of all threads in ready queue are less than that of currently//      executing thread. The invariant does not hold until the next //      event when the scheduler is invoked.//----------------------------------------------------------------------voidThread::Yield (){    Thread *nextThread;    IntStatus oldLevel = interrupt->SetLevel(IntOff);        ASSERT(this == currentThread);        DEBUG('t', "Yielding thread \"%s\"\n", getName());        nextThread = scheduler->FindNextToRun();    if (nextThread != NULL) {	scheduler->ReadyToRun(this);	scheduler->Run(nextThread);    }    (void) interrupt->SetLevel(oldLevel);}//----------------------------------------------------------------------// Thread::Sleep// 	Relinquish the CPU, because the current thread is blocked//	waiting on a synchronization variable (Semaphore, Lock, or Condition).//	Eventually, some thread will wake this thread up, and put it//	back on the ready queue, so that it can be re-scheduled.////	NOTE: if there are no threads on the ready queue, that means//	we have no thread to run.  "Interrupt::Idle" is called//	to signify that we should idle the CPU until the next I/O interrupt//	occurs (the only thing that could cause a thread to become//	ready to run).////	NOTE: we assume interrupts are already disabled, because it//	is called from the synchronization routines which must//	disable interrupts for atomicity.   We need interrupts off //	so that there can't be a time slice between pulling the first thread//	off the ready list, and switching to it.//----------------------------------------------------------------------voidThread::Sleep (){    Thread *nextThread;        ASSERT(this == currentThread);    ASSERT(interrupt->getLevel() == IntOff);        DEBUG('t', "Sleeping thread \"%s\"\n", getName());    status = BLOCKED;    while ((nextThread = scheduler->FindNextToRun()) == NULL)	interrupt->Idle();	// no one to run, wait for an interrupt            scheduler->Run(nextThread); // returns when we've been signalled}//----------------------------------------------------------------------// ThreadFinish, InterruptEnable, ThreadPrint//	Dummy functions because C++ does not allow a pointer to a member//	function.  So in order to do this, we create a dummy C function//	(which we can pass a pointer to), that then simply calls the //	member function.//----------------------------------------------------------------------static void ThreadFinish()    { currentThread->Finish(); }static void InterruptEnable() { interrupt->Enable(); }void ThreadPrint(int arg){ Thread *t = (Thread *)arg; t->Print(); }//----------------------------------------------------------------------// Thread::StackAllocate//	Allocate and initialize an execution stack.  The stack is//	initialized with an initial stack frame for ThreadRoot, which://		enables interrupts//		calls (*func)(arg)//		calls Thread::Finish////	"func" is the procedure to be forked//	"arg" is the parameter to be passed to the procedure//----------------------------------------------------------------------voidThread::StackAllocate (VoidFunctionPtr func, int arg){    stack = (int *) AllocBoundedArray(StackSize * sizeof(int));#ifdef HOST_SNAKE    // HP stack works from low addresses to high addresses    stackTop = stack + 16;	// HP requires 64-byte frame marker    stack[StackSize - 1] = STACK_FENCEPOST;#else    // i386 & MIPS & SPARC stack works from high addresses to low addresses#ifdef HOST_SPARC    // SPARC stack must contains at least 1 activation record to start with.    stackTop = stack + StackSize - 96;#else  // HOST_MIPS  || HOST_i386    stackTop = stack + StackSize - 4;	// -4 to be on the safe side!#ifdef HOST_i386    // the 80386 passes the return address on the stack.  In order for    // SWITCH() to go to ThreadRoot when we switch to this thread, the    // return addres used in SWITCH() must be the starting address of    // ThreadRoot.    *(--stackTop) = (int)ThreadRoot;#endif#endif  // HOST_SPARC    *stack = STACK_FENCEPOST;#endif  // HOST_SNAKE        machineState[PCState] = (int) ThreadRoot;    machineState[StartupPCState] = (int) InterruptEnable;    machineState[InitialPCState] = (int) func;    machineState[InitialArgState] = arg;    machineState[WhenDonePCState] = (int) ThreadFinish;}#ifdef USER_PROGRAM#include "machine.h"//----------------------------------------------------------------------// Thread::SaveUserState//	Save the CPU state of a user program on a context switch.////	Note that a user program thread has *two* sets of CPU registers -- //	one for its state while executing user code, one for its state //	while executing kernel code.  This routine saves the former.//----------------------------------------------------------------------voidThread::SaveUserState(){    for (int i = 0; i < NumTotalRegs; i++)	userRegisters[i] = machine->ReadRegister(i);}//----------------------------------------------------------------------// Thread::RestoreUserState//	Restore the CPU state of a user program on a context switch.////	Note that a user program thread has *two* sets of CPU registers -- //	one for its state while executing user code, one for its state //	while executing kernel code.  This routine restores the former.//----------------------------------------------------------------------voidThread::RestoreUserState(){    for (int i = 0; i < NumTotalRegs; i++)	machine->WriteRegister(i, userRegisters[i]);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -