1 / 27

Nachos Instructional OS

Nachos Instructional OS. CS 170, Tao Yang, Fall 2011. What is Nachos OS?. Allow students to examine, modify and execute operating system software. A skeletal OS that supports kernel threads user-level processes Simulates MIPS instruction execution.

hairj
Download Presentation

Nachos Instructional OS

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Nachos Instructional OS CS 170, Tao Yang, Fall 2011

  2. What is Nachos OS? • Allow students to examine, modify and execute operating system software. • A skeletal OS that supports • kernel threads • user-level processes • Simulates MIPS instruction execution. • Running on a virtual machine, executed as a single Unix process in a hosting OS. • Over 9K lines of C++ code. • Can understand its basic mechanisms by reading about 1-2K lines of code.

  3. System Layers User process User process Nachos kernel threads Thread 1 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)

  4. Steps to Install Nachos • Obtain and install Nachos source code. • Copy the source code from ~cs170/nachosSept20.tar.gz • Compile the source code with Makefile • Run Nachos demo • 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 4.

  5. Nachos code directory • machine --- Basic machine specification (MIPS simulator). • threads --- threads management (HW1). • userprog -- binary code execution and system calls (HW2). • vm -- virtual memory (HW3). • filesys -- file system (HW3) • test -- binary test code • network -- networking protocol • bin -- utilities/tools (binary format conversion)

  6. Source code reading and HW1 Objectives of next 2 weeks • Scan through ~1,000-2,000 lines of code under threads directory • Learn how context switch is accomplished among threads. • Learn how thread scheduling is done. • Learn how locks/synchronization are implemented and used. • Complete HW1 • Few hundred lines of code • Sample code is available

  7. Single-threaded vs multithreaded Process

  8. Sample Example of Nacho Threads int shared=1; main () { Thread *t1 = new Thread("forked thread1"); Thread *t2 = new Thread("forked thread2"); t1->Fork(SimpleThread, 1); t2->Fork(SimpleThread, 2); SimpleThread(3); } SimpleThread(int i) { printf(“Hello %d. Shared %d\n”, i, shared); currentThread->Yield(); } Create 2 new threads. Start to fork and execute a function in each child thread. Parent also executes the same function Function executed by threads

  9. Nachos Threads • Each thread has the following TCB (thread control block) from thread.h int *stackTop; // stack pointer int machineState[18]; // copy of registers int *stack // bottom of stack ThreadStatus status; //ready, running, or blocked char *name; • Thread operations: • Thread(char *debugName). Create a thread. • Fork(VoidFunctionPtr func, int arg). Let a thread execute a function. • Yield(). Suspend the calling thread and select a new one for execution. • Sleep(). Suspend the current thread, change its state to BLOCKED, and remove it from the ready list • Finish()

  10. Nachos Thread States and Transitions running (user) When running in user mode, the thread executes within the machine simulator. HW 2 covers this. In HW 1 we are only concerned with the states in this box. Machine::Run, ExceptionHandler interrupt or exception Thread::Yield running (kernel) Thread::Sleep Scheduler::Run blocked ready Scheduler::ReadyToRun

  11. Reading source code • Have a picture of overall components and their roles. • Nacho code structure • Be able to compile and run a simple case. • Follow Project 0 and execute two cases. • Trace the code execution through a simple case • Basic/high level mechanism involved in execution. • Walk through a simple thread test case in Nachos. Week 2 link in http://www.cs.ucsb.edu/~cs170/refer.html

  12. Key steps when Nachos executes After you type ``nachos'' under threads subdirectory: • It is executing as a single Unix process. • The main() calls • Initialize() to start up interrupt handling, create a scheduler for managing the ready queue. • ThreadTest() (to be explained for HW 1). • currentThread->Finish() to let other threads continue to run.

  13. Key Calling graph when Nachos executes under thread directory StackAllocate() in thread.cc All files are in threads directory. Thread:Fork () in thread.cc Initialize() in system.cc SWITCH () in switch.s FindNextToRun () in scheduler.cc Thread:Yield () in thread.cc main() in main.cc ThreadRoot () in switch.s ReadyToRun () in scheduler.cc ThreadTest () in threadtest.cc func() such as SimpleThread() in ThreadTest.cc Run () in scheduler.cc currentThread->Finish () in threadtest.cc

  14. Scheduler object for thread scheduling • A scheduler decides which thread to run next by scanning the ready list. • The scheduler is invoked whenever the current thread gives up the CPU. • The current Nachos scheduling policy is round-robin: new threads are appended to the end of the ready list, and the scheduler selects the front of the list. • The Scheduler object has the following operations: • ReadyToRun(Thread *thread). Make thread ready to run and place it on the ready list. • Thread *FindNextToRun() • Run(Thread *nextThread)

  15. Thread Switching • Switching involves suspending current thread, saving its state, and restoring the state of new thread. • Following code involved in execution: the old code, the new code, and the code that performs switching. • Switch(oldThread, newThread): • Save all registers in oldThread's context block. • Save the program address to be used when the old thread is resumed. • Load new values into the registers from the context block of the new thread. • Once the saved PC of the new thread is loaded, Switch() is no longer executing.

  16. Key operations of SWITCH() Thread->Fork(func(), arg) Save current thread context Call InterruptEnable() SWITCH () in switch.s Load target thread context func(arg) Call func(arg) Call ThreadRoot () in switch.s Call ThreadFinish()

  17. Assembly code of SWITCH(oldThread, nextThread) • # a0 -- pointer to old thread’s TCB a1 -- pointer to new thread’sTCB • Save register values to current thread’s TCB sw sp, SP(a0) # save new stack pointer sw s0, S0(a0) sw s1, S1(a0) sw s2, S2(a0) sw s3, S3(a0) sw s4, S4(a0) sw s5, S5(a0) sw s6, S6(a0) sw s7, S7(a0) sw fp, FP(a0) sw ra, PC(a0) # save return address a0 sp stackTop machineState[0] machineState[1] machineState[2] … s0 s1 s2 …

  18. Assembly code of SWITCH(oldThread, nextThread) • # a0 -- pointer to old thread’s TCB a1 -- pointer to new thread’sTCB • Load registers from new thread’s TCB lw sp, SP(a1) # load the new stack pointer lw s0, S0(a1) lw s1, S1(a1) lw s2, S2(a1) … lw s7, S7(a1) lw fp, FP(a1) lw ra, PC(a1) # load the return address j ra #Call ra which is ThreadRoot(); a1 sp stackTop machineState[0] machineState[1] machineState[2] machineState[3] … machineState[9] s0 s1 s2 s3 ra

  19. Assembly code of SWITCH(oldThread, nextThread) • # a0 -- pointer to old thread’s TCB a1 -- pointer to new thread’sTCB • Load registers from new thread’s TCB lw sp, SP(a1) # load the new stack pointer lw s0, S0(a1) lw s1, S1(a1) lw s2, S2(a1) … lw s7, S7(a1) lw fp, FP(a1) lw ra, PC(a1) # load the return address j ra #Call ra which is ThreadRoot(); a1 sp stackTop func() arg ThreadFinish() InterruptEnable() … ThreadRoot() addr s0 s1 s2 s3 ra

  20. Who fills values of the new thread TCB properly? • StackAllocate() in Thread::Fork() fills values of machineState[]; machineState[PCState] = (int) ThreadRoot; // PCState=9 machineState[StartupPCState] = (int) InterruptEnable; //StartupPCState=3 machineState[InitialPCState] = (int) func; //InitialPCState=0 machineState[InitialArgState] = arg; //InitialArgState=1 machineState[WhenDonePCState] = (int) ThreadFinish; //WhenDonePCState=2

  21. Does ThreadRoot() use s0, s1,s2,s3 to execute targeted thread func()? jal StartupPC # call InterruptEnable() stored in register s3 move a0, InitialArg #move argument in s1 to a0 jal InitialPC # call main thread procedure func() stored in s0 jal WhenDonePC # when done, call ThreadFinish() in s2

  22. QA • When will thread:Finish() be called? • At the end of the forked thread. Check ThreadRoot assembly code. • At the end of the main() thread. • Thread:Finish() calls scheduler->run() to run a new thread. Will the old thread (that calls Thread:Finish()) be returned and continue to be executed? • No. Because the following is called first. threadToBeDestroyed = currentThread; • Scheduler->Run() will delete such TCB

  23. QA • In Sleep() or Yield(), the interrupt is turned off before calling scheduler->() to execute another thread. • When will interrupt be turned on? • In executing the switched thread, ThreadRoot() assembly code first executes StartupPC function which is • machineState[StartupPCState] = (int) InterruptEnable;

  24. Semaphore object for thread synchronization • Disable and re-enable interrupts to achieve mutual exclusion (e.g., by calling Interrupt::SetLevel()). • Operations for a Semaphore object: • Semaphore(char* debugName, int initialValue) • P(): Decrement the semaphore's count, blocking the caller if the count is zero. • V() :Increment the semaphore's count, releasing one thread if any are blocked waiting on the count.

  25. HW 1: threads & synchronization • Work under threads subdirectory. • Modify ThreadTest() to do simple threads programming (spawning multiple threads). • Implement locks and condition variables (missing from the file synch.cc). • Workload: • Read Nachos code and add few hundred lines of code. • Undocumented sample solution is provided.

  26. HW 1: Files involved Key files • 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 thread ready list. • synch.h synch.cc -- synchronization routines. Other related files. • synchlist.h, synchlist.cc -- synchronized access to lists using locks/conditions (useful examples for your programming). • list.h list.cc -- generic list management. • system.h, system.cc -- Nachos startup/shutdown routines. • utility.h utility.cc -- some useful definitions and debugging routines. • interrupt.h interrupt.cc -- manage interrupts. • time.h timer.cc -- clock emulation. • switch.h, switch.s -- assembly code for thread switching. • stats.h stats.cc -- collect interesting statistics.

  27. HW Sample Code ~cs170/nachos-projtest/Proj2Sample.tar.gz • Has an old solution for HW1, HW2, HW3 • HW1  threads subdirectory. ~400 lines of new code. • HW2 -> userprog subdirectory. ~1200 lines of new code. Code for Exec() and Read() is not included. • HW3 -> Not included. • Caveat: • Mixed benefits/problems in using other students’ code. e.g. Not well documented, not fully tested. Possibly awkward style/design • Still your responsibility to produce good solutions (correctness, performance, style) with at least 50% difference

More Related