Nachos Instructional OS CS 170 Tao Yang Fall































![Sample/Makefile, and test script [cs 170@csil PROJECT 1]$ more testscript make clean; make threads/nachos Sample/Makefile, and test script [cs 170@csil PROJECT 1]$ more testscript make clean; make threads/nachos](https://slidetodoc.com/presentation_image/d8eeb030139eb5a1834c1bb6e0a444d7/image-32.jpg)






- Slides: 38
Nachos Instructional OS CS 170, Tao Yang, Fall 2012
Why Nachos OS? n Learn by reading and modifying simple operating system code n n Extremely important OS experience A skeletal OS that supports n kernel threads, user-level processes n MIPS instruction execution as a virtual machine n ~9 K lines of C++ code. 10/6/2020 2
System Layers User process Thread 1 User process Nachos kernel threads Thread 2 Thread N Nachos OS modules (Threads mgm, File System, Code execution/memory mapping, System calls/Interrupt) Simulated MIPS Machine (CPU, Memory, Disk, Console) Base Operating System (Linux for our class)
Project 1 Tasks 1 -3 main() Thread. Test() Thread 1 Nachos threads Thread 2 Nachos OS modules Simulated MIPS Machine Linux Thread N
Steps to Install Nachos n Obtain and install Nachos source code. n n n Compile the source code with Makefile Run Nachos demo n n n Copy the source code from ~cs 170/nachos. Sept 20. tar. gz Under the threads subdirectory (run threads) Under the userprog subdirectory (compile/execute binary code) Project 0: Form a group/turn-in proj 0. Due on Oct 10 10/6/2020 5
Nachos code directory n n n n machine --- Basic machine specification (MIPS simulator as a virtual machine). threads --- threads management (Project 1). userprog -- binary code execution and system calls (Project 2). vm -- virtual memory (empty, Project 3). filesys -- file system (Project 3) test -- binary code to be executed in this virtual machine network -- networking protocol (not used in this class) bin -- utilities/tools (binary format conversion) 10/6/2020 6
Source code reading and Project 1 Objectives of next 2 weeks n Scan through ~1, 000 -2, 000 lines of code under threads directory n n n Learn how context switch is accomplished among threads. Learn how thread scheduling is done. Learn how locks/synchronization are implemented and used. Use Linux pthreads. Complete Project 1 10/6/2020 7
Sample Example of Nacho Threads int shared=1; main () { Thread *t 1 = new Thread("forked thread 1"); Thread *t 2 = new Thread("forked thread 2"); t 1 ->Fork(Simple. Thread, 1); t 2 ->Fork(Simple. Thread, 2); Create 2 new threads. Start to fork and execute a function in each child thread. Parent also executes the same function Simple. Thread(3); } Simple. Thread(int i) { printf(“Hello %d. Shared %dn”, i, shared); current. Thread->Yield(); } Function executed by threads
Nachos Threads n n Each thread has the following TCB (thread control block) from thread. h int *stack. Top; // stack pointer int machine. State[18]; // copy of registers int *stack // bottom of stack Thread. Status status; //ready, running, or blocked char *name; Thread operations: n Thread(char *debug. Name). Create a thread. n Fork(Void. Function. Ptr func, int arg). Let a thread execute a function. n Yield(). Suspend the calling thread and select a new one for execution. n Sleep(). Suspend the current thread, change its state to BLOCKED, and remove it from the ready list n Finish() 10/6/2020 9
Nachos Thread States and Transitions Thread: : Yield running (kernel) Thread: : Sleep blocked Scheduler: : Run Scheduler: : Ready. To. Run ready
Semaphore object for thread synchronization n n Disable and re-enable interrupts to achieve mutual exclusion (e. g. , by calling Interrupt: : Set. Level()). Operations for a Semaphore object: n Semaphore(char* debug. Name, int initial. Value) n P(): Decrement the semaphore's count, blocking the caller if the count is zero. n V() : Increment the semaphore's count, releasing one thread if any are blocked waiting on the count. 10/6/2020 11
Semaphore Implementation n n Atomic critical section n P(S) { while ( S <= 0) ; // wait S--; } n V(S) { S++; } Issue in busy waiting n Waste time n Applications may spend lots of time in such a critical section
Semaphore Implementation with no busy waiting Each semaphore has a waiting queue. n n Two internal operations: n Sleep– place thread invoking the operation on the waiting queue. n Nachos: Thread: Sleep() n wakeup – remove one thread in the waiting queue and place it in the ready queue.
Semaphore Implementation with no Busy waiting (Cont. ) n P(semaphore *S) { S->value--; if (S->value < 0) { add this thread to waiting-queue; sleep(); }} n V(semaphore *S) { S->value++; if (S->value <= 0) { Remove x from waiting-queue; wakeup(x); }}
Reading source code n n Have a picture of overall components and their roles. Be able to compile and run a simple case. n n Follow Project 0 and execute two cases. Trace the code execution through a simple case n Basic/high level mechanism involved in execution. n Walk through a simple thread test case in Nachos. Week 2 link in http: //www. cs. ucsb. edu/~cs 170/refer. html 10/6/2020 15
Project 1 Tasks 1 -3 main() Thread. Test() Thread 1 Nachos threads Thread 2 Nachos OS modules Simulated MIPS Machine Linux Thread N
Key steps when Nachos executes After you type ``nachos'' under threads subdirectory: n It is executing as a single Unix process. n The main() calls n Initialize() to start up interrupt handling, create a scheduler for managing the ready queue. n Thread. Test() n current. Thread->Finish() to let other threads continue to run. 10/6/2020 17
Key Calling graph when Nachos executes under thread directory All files are in threads directory. Thread: Fork () in thread. cc Initialize() in system. cc main() in main. cc Thread: Yield () in thread. cc Thread. Test () in threadtest. cc current. Thread->Finish () in threadtest. cc 10/6/2020 Stack. Allocate() in thread. cc Find. Next. To. Run () in scheduler. cc SWITCH () in switch. s Ready. To. Run () in scheduler. cc Thread. Root () in switch. s Run () in scheduler. cc func() such as Simple. Thread() in Thread. Test. cc 18
Key Calling graph for Project 1 Task 1 All files are in threads directory. Initialize() in system. cc main() in main. cc Spawn multiple threads. Each executes a sample loop. Finally print shared variable at the end Thread: Fork () in thread. cc Thread: Yield () in thread. cc Thread. Test () in threadtest. cc current. Thread->Finish () in threadtest. cc 10/6/2020 Semaphore P()/V() in synch. cc 19
Key Calling graph for Project 1 Task 3 All files are in threads directory. Initialize() in system. cc main() in main. cc Spawn multiple threads as test stations Thread: Fork () in thread. cc Each executes allocate() and release() operations Thread. Test () in threadtest. cc current. Thread->Finish () in threadtest. cc 10/6/2020 Lock/conditions in synch. cc 20
Scheduler object for thread scheduling n n n Decide which thread to run next n Invoked when the current thread gives up CPU. The current Nachos scheduling policy is round-robin: n Select the front of ready list. n Append new threads to the end. Key operations: n Ready. To. Run(Thread *thread). Make thready to run and add to ready list. n Thread *Find. Next. To. Run() n Run(Thread *next. Thread) 10/6/2020 21
Thread Switching n n Suspend current thread, save its state, and restore the state of new thread. Switch(old. Thread, new. Thread): n Save all registers in old. Thread's TCB. n n to be used when the old thread is resumed. Load new values into the registers from TCB of the new thread. 10/6/2020 22
Single-threaded vs multithreaded Process 10/6/2020 23
Key operations of SWITCH() Thread->Fork(func(), arg) Save current thread context SWITCH () in switch. s func(arg) Load target thread context Call Thread. Root () in switch. s 10/6/2020 Call Interrupt. Enable() Call func(arg) Call Thread. Finish() 24
SWITCH(old. Thread, next. Thread) Save register values to current thread’s TCB n # a 0 -- pointer to old thread’s TCB sw sw sw sp, SP(a 0) # save new stack pointer s 0, S 0(a 0) s 1, S 1(a 0) s 2, S 2(a 0) s 3, S 3(a 0) s 4, S 4(a 0) s 5, S 5(a 0) s 6, S 6(a 0) s 7, S 7(a 0) fp, FP(a 0) ra, PC(a 0) # save return address a 1 -- pointer to new thread’s. TCB a 0 TCB Registers sp s 0 s 1 s 2 save stack. Top machine. State[0] machine. State[1] machine. State[2] … … 10/6/2020 25
Load register values from new thread’s TCB n lw lw … lw lw lw # a 0 -- pointer to old thread’s TCB sp, s 0, s 1, s 2, a 1 -- pointer to new thread’s. TCB SP(a 1) # load the new stack pointer S 0(a 1) S 1(a 1) S 2(a 1) s 7, S 7(a 1) fp, FP(a 1) ra, PC(a 1) # load the return address j ra #Call ra which is Thread. Root(); a 1 sp s 0 s 1 s 2 s 3 stack. Top machine. State[0] machine. State[1] machine. State[2] machine. State[3] … machine. State[9] ra 10/6/2020 26
How TCB is initialized? n # a 0 -- pointer to old thread’s TCB a 1 -- pointer to new thread’s. TCB n a 1 lw lw … lw lw lw sp, s 0, s 1, s 2, SP(a 1) # load the new stack pointer S 0(a 1) S 1(a 1) sp S 2(a 1) s 0 s 7, S 7(a 1) fp, FP(a 1) ra, PC(a 1) # load the return address j ra #Call ra which is Thread. Root(); 10/6/2020 s 1 s 2 s 3 stack. Top func() arg Thread. Finish() Interrupt. Enable() … Thread. Root() addr ra 27
Which routine fills values of the new thread TCB? n Stack. Allocate() in Thread: : Fork() machine. State[PCState] = (int) Thread. Root; // PCState=9 machine. State[Startup. PCState] = (int) Interrupt. Enable; //Startup. PCState=3 =>s 3 machine. State[Initial. PCState] = (int) func; //Initial. PCState=0 =>s 0 machine. State[Initial. Arg. State] = arg; //Initial. Arg. State=1 =>s 1 machine. State[When. Done. PCState] = (int) Thread. Finish; //When. Done. PCState=2 =>s 2 n bb 10/6/2020 28
Thread. Root() uses registers s 0, s 1, s 2, s 3 to execute targeted func() jal Startup. PC move a 0, Initial. Arg jal Initial. PC jal # call #move argument in s 1 to a 0 # call main thread procedure func() stored in s 0 When. Done. PC 10/6/2020 Interrupt. Enable() stored in register s 3 # when done, call Thread. Finish() in s 2 29
Project 1 Objectives n Tasks 1 -3 under threads subdirectory. n n Gain experience with simple thread programming (execute multiple Nachos threads with synchronization). Implement locks and condition variables (missing from the file synch. cc). Use for laundromat application Task 4 under hw 1_task 1_pthreads subdirectory n Show that Pthreads code works similarly 10/6/2020 30
Tasks 1/2/3: Nachos Files involved Key files to read and modify (modify 3 files in red) n n n main. cc, threadtest. cc -- a simple test of our thread routines. thread. h thread. cc -- Nachos thread data structure and operations. scheduler. h scheduler. cc -- The thready list. synch. h synch. cc -- synchronization routines. system. h, system. cc -- Nachos startup initialization /shutdown switch. h, switch. s -- assembly code for thread switching. Other related files: n n n synchlist. h, synchlist. cc -- synchronized access to lists using locks/conditions (useful examples for your programming). list. h list. cc -- generic list management. utility. h utility. cc -- some useful definitions and debugging routines. interrupt. h interrupt. cc -- manage interrupts. time. h timer. cc -- clock emulation. stats. h stats. cc -- collect interesting statistics. 10/6/2020 31
Sample/Makefile, and test script [cs 170@csil PROJECT 1]$ more testscript make clean; make threads/nachos > Task 1 -1_trace make clean; make "DEFINES = -DTHREADS -DHW 1_SEMAPHORES" threads/nachos > Task 1 -2_trace make clean; make "DEFINES = -DTHREADS -DHW 1_LAUNDRY_LC" threads/nachos > Task 3_trace cd hw 1_task 1_pthreads make; make run >Task 4_trace 10/6/2020 32
Sample Code for Tasks 1/2/3 ~cs 170/sample/PRJECT 1/ n Has an incomplete sample solution for Project 1 n <~50 lines of sample code are removed. n Removed positions are marked n Caveat: n Not well documented, not fully tested. Possibly awkward style/design n Still your responsibility to produce good solutions (correctness, performance, style) with at least 50% difference 10/6/2020 33
Task 1 (1): Use Nachos threads and explain behavior int Shared. Variable; void Simple. Thread(int which) { int num, val; for(num = 0; num < 5; num++) { val = Shared. Variable; printf("*** thread %d sees value %dn", which, val); current. Thread->Yield(); Shared. Variable = val+1; current. Thread->Yield(); } val = Shared. Variable; printf("Thread %d sees final value %dn", which, val); } n 10/6/2020 34
Task 1 (2): Use Nachos semaphores to synchronize int Shared. Variable; void Simple. Thread(int which) { int num, val; for(num = 0; num < 5; num++) { val = Shared. Variable; printf("*** thread %d sees value %dn", which, val); Critical section needs a mutual execution current. Thread->Yield(); Shared. Variable = val+1; Need a barrier so every thread sees the current. Thread->Yield(); same value of “Shared. Variable” } val = Shared. Variable; printf("Thread %d sees final value %dn", which, val); } n 10/6/2020 35
Task 2: Lock/condition variable implementation Implement Lock code in synch. cc similar as Nachos semaphore code n Sample solution is available n Implement conditional variables n A few lines were removed from the sample code. n 10/6/2020 36
Task 4: Use Pthreads instead Nachos for Task 1 (2) Use pthread_create() to execute int Shared. Variable; void Simple. Thread(int which) { int num, val; for(num = 0; num < 5; num++) { val = Shared. Variable; Use pthread_yield() printf("*** thread %d sees value %dn", which, val); Use pthread_mutex_lock/unlock(), current. Thread->Yield(); Shared. Variable = val+1; current. Thread->Yield(); Barrier using pthread_mutex_lock()/unlock() } pthread_cond_wait(), /cond_broadcast() val = Shared. Variable; printf("Thread %d sees final value %dn", which, val); } n 10/6/2020 37
Implementation Strategy for Project 1 n n n Read key Nachos files listed in the previous slide. Find difference between sample solution with the existing code: main. cc, threadtest. cc, synch. cc. Find what is removed (search “removed”) Implement Task 1 using semaphore Implement Task 2 using code similar to semaphore implementation in synch. cc (check how sample solution implements lock). Implement Task 3 using lock/conditions with 2 stations (sample solution). Then test with 3 stations. For Task 4, study related Pthread functions, model Task 1 using Pthreads, and synchronize with its lock/condition variables 10/6/2020 38