Chapter 1 Process and Thread
1.2 process The address space of a program – Text – Code – Stack – Heap A set of registers – PC – SP Other resources – Files – Sockets A process is a virtual machine
Virtual machines PID PCB CPU switch
1.3 Thread A set of registers – PC – SP A stack Processes and threads share many concepts in common – States and State Transition – Control Block – Context Switch Differences A thread is a virtual CPU
1.4 Thread and Process Control Block A thread in Nachos is implemented as an object of class Thread in the kernel. The control block of a thread is implemented as part of data members of this class
Thread creation Thread creation (thread.cc) – sets up the thread name – sets status to JUST CREATED ) Thread status – JUST_CREATED – RUNNING – READY – BLOCKED
Thread creation A thread has two sets of CPU registers – system registers used for running the kernel userRegisters[] – user registers used for running user programs machineState[] Threads in a process share the same address space
Process Creation Each user process in Nachos starts with a kernel thread After having loaded the user program and formed the address space in the memory, the kernel thread becomes a user process.
1.5 Thread and Process Scheduling the job scheduler is implemented as an object of class Scheduler When Nachos is started, an object of class Scheduler is created and referenced by a global variable scheduler
Definition of Class Scheduler Ready queue ReadyToRun(Thread* thread) – puts the thread at the end of the queue FindNextToRun() – returns the pointer to the thread removed from the queue Run(Thread*) – calls the assembly function SWITCH(Thread*, Thread*) for the context switch from the current thread
1.6 Thread and Process State Transition Fork(VoidFunctionPtr func, _int arg) – JUST CREATED to READY Yield() – RUNNING to READY Sleep() – RUNNING to BLOCKED Finish() – terminate the thread
1.7 Thread Creation Thread::Thread(char* threadName) { name = threadName; stackTop = NULL; stack = NULL; status = JUST_CREATED; #ifdef USER_PROGRAM space = NULL; #endif } Thread object construction merely creates the data structure of the object and sets its state to JUST CREATED
Fork() This thread is not ready to run yet – Its control block has not been initialized – its stack has not been allocated – it does not have the initial value for PC StackAllocate (VoidFunctionPtr, int ) – allocate the memory space for the stack – initialize the array machineState[] interrupt->SetLevel(IntOff )
Thread::Fork(VoidFunctionPtr func, _int arg)
StackAllocate (VoidFunctionPtr, int ) AllocBoundedArray(int) – allocates a stack Set up registrstors – machineState[PCState] = (_int) ThreadRoot; – machineState[StartupPCState] = (_int) InterruptEnable – machineState[InitialPCState] = (_int) func – machineState[InitialArgState] = arg – machineState[WhenDonePCState] = (_int) ThreadFinish
ThreadRoot ra is called return address register and contains the address of the first instruction to execute after the assembly routine is complete machineState[PCState] refers to function ThreadRoot machineState[PCState] is loaded into register ra The first routine executed by the new thread is ThreadRoot
When a thread is scheduled to run for the first time, the value in machineState[PCState] which is the reference to function ThreadRoot, is loaded into register ra. ra is called return address register and contains the address of the first instruction to execute after the assembly routine is complete. Therefore, the first routine executed by the new thread is ThreadRoot
ThreadRoot
ThreadRoot’s function A wrapper which calls three subroutines – StartupPC : InterruptEnable simply to enable interrupt – InitialPC – ThreadFinish terminate the thread. Subroutine ThreadRoot defines the activities of the thread during its life time
InitialPC The reference of the function we want the thread to execute for the real job is in register InitialPC, and its argument in register InitialArg jal Reg is called “jump and link – It saves the return address in hardware – jumps to the subroutine pointed by register Reg
1.8 Context Switch a context switch is started by calling function Run (Thread *) of class Scheduler
Key global variables currentThread is the pointer to the current running thread scheduler is the pointer to the Scheduler object of the kernel – created when the Nachos kernel is started – Created by Initialize(int argc, char **argv)
Run (Thread *nextThread) sets variables – oldThread to the the current running thread (the thread which calls this function) – currentThread to the next thread 设置新进程状态 SWITCH – 参见 P23 Delete the carcasses of finished processes
SWITCH(..) saves all the important registers of the current thread Recall that the first private data member of Thread class is stackTop followed by achineState[MachineStateSize] register ra contains the the return address of the function call. In this case, ra contains the address of the instruction right after line 116 in scheduler.cc The instruction in line 113 makes the control jump to the address stored in ra
Note: Two return points the lines and lines in function Run(Thread*), are used to save and restore the user registers and the address space of user processes The entire function Run(Thread*) is run by the kernel, because it belongs to the Nachos kernel Two return points: – From the other thread to – From kernel to user
Note: The time of the return Note the time of the return of function call Run(Thread*) to the current thread. It does not return immediately. It won’t return until the calling thread is switched back and becomes the current thread again – Thread X gives up CPU by call Run() SWITCH() – SWITCH() activates another thread Y – After Y, the CPU maybe not return to X
1.9 Thread Termination ThreadRoot calls function Finish() Finish() – sets threadToBeDestroyed to current thread – then calls Sleep() The termination of this thread is actually done by the next thread after the context switch A thread can’t delete itself
1.11 Operating Systems Kernel The smallest Nachos kernel – containing thread management only – call (void) Initialize(argc, argv) – call ThreadTest() – call currentThread->Finish() Explain P25,26