Introduction TDDB63 Nachos - Lesson 1 • Alexandru Andrei • alean@ida.liu.se • /liu/ida/eslab • Course: Concurrent Programming and Operation Systems TDDB63 • Homepage: http://www.ida.liu.se/~TDDB63/ check regularly read messages section -2- Laboratory Sessions Laboratory Assignments • Lesson 1 – Lab 0: Nachos Overview – Lab 0: C/C++ Intro • – Lab 1: Threads and Synchronization • Lesson 2 • – Lab 2: System Calls • Lesson 3 – Lab 3: Memory Management -3- 7''% /DEOHVVRQ Labs build upon the previous labs Lab 3 is (usually) the most time consuming TDDB63 Lab lesson TDDB63 Lab lesson • • • • SU rooms Sun machines C/C++ Check the web page for setting up gcc 2.8.1 (module add prog/gcc-2.8.1) • • • • Be prepared Tools: emacs(or another editor), gmake, ddd, man => No support without using debugger before! Mark your changes in the source code -4- TDDB63 Lab lesson Laboratory Sessions • Documentation Laboratory Sessions • Marking changes – A readme file which contains: • The files you have created and a short description • The major changes you have made to the given files – A testcase file which contains: • Which test cases did you use • What was the output of the test cases • What those testcases should demonstrate -5- // -----------------------------------------------// 04-01-24: your_name: changed ... // end of changes // ------------------------------------------------ TDDB63 Lab lesson -6- Laboratory Sessions • File header Laboratory Sessions • Function header // ========================================== // TDDB63: Lab 1: solution.cpp // -----------------------------------------------// Group XYZ: Mister X / Miss Y // -----------------------------------------------// This module extends Nachos to be able to work // with semaphores. // -----------------------------------------------// 00-02-01: misterX: created // 99-02-12: missY: semSignal: changed signal type // =========================================== -7- 7''% /DEOHVVRQ TDDB63 Lab lesson TDDB63 Lab lesson // -----------------------------------------------// int readInput(int file) // -----------------------------------------------// This function reads continuously from the // file and returns the number of bytes read // -----------------------------------------------// Parameters: // file: handle of the file to read from // ------------------------------------------------ -8- TDDB63 Lab lesson Tips • “Not Another Completely Heuristic Operating System” • Free operating system and simulation environment to study an operating system • Runs as a single Unix process (real operating systems run on bare machines) • Simulates low-level facilities (including interrupts, virtual memory and interrupt-driven device I/O) • Implemented in subset of C++, ca. 2.500 lines of code • Read documentation and source code – Nachos Beginner’s Guide (html) – A Roadmap Through Nachos (pdf) • • • • Nachos Overview {} Use a debugger (gdb / ddd) Use code browsing tools (emacs, grep) Use different test cases Read homepage regularly • See homepage material and links • Read/understand source code !!!!!!! TDDB63 Lab lesson TDDB63 Lab lesson -10- Overview} • Nachos simulates a machine approximating a real machines architecture • Has: Nachos code/machine – Registers, Memory, CPU, interrupts – Event-driven simulated clock OS KERNEL • Can execute arbitrary programs • Two modes: simulator (running programs) and “kernel mode” (starting up or reacting on hardware traps) -11- 7''% /DEOHVVRQ code/threads code/userprog TDDB63 Lab lesson *LYHQ code/test Test programs -9- /DE -12- TDDB63 Lab lesson Machine Object • Available through variable machine • Public attributes: • Nachos simulates interrupts with an event queue and a clock (clock ticks -> queue is examined for pending events) • The clock ticks, when ... – registers – mainMemory – virtualMemory (single linear page and software-managed TLB) – Interrupts are restored (used often for mutual exclusion purposes) – One instruction is executed – “Ready list” is empty • Methods: Machine (constructor), Translate (translates virtual addresses), OneInstruction, Run, ReadRegister, WriteRegister, ReadMem, WriteMem => Read documentation and source code -13- Interrupt Management • Object Interrupt: – Main methods: Schedule (schedule event), SetLevel (disable / enable), OneTick => Read documentation / source code TDDB63 Lab lesson -14- Real-Time Clock Interrupts TDDB63 Lab lesson Address Translation • Nachos supports two virtual memory architectures: • Object Timer: – Simulates a real-time clock (generates interrupts at regular intervals) – Methods: Timer (creates a real-time clock, can be randomly influenced) – ./nachos –rs #number (nachos –rs 100) – Linear page tables (easier to program) – Software-managed TLB (closer to what current machines support) – Only one at a time • Linear page tables: – Virtual address: page number and page offset – Physical address: machine->mainMemory + n * PageSize + m • Read documentation / source code -15- 7''% /DEOHVVRQ TDDB63 Lab lesson -16- TDDB63 Lab lesson Terminal Console Device • Accessed through low-level primitives (initiated by I/O operation, performed by an “operation complete” interrupt) Disk Device • Accessed through low-level primitives (initiated by I/O operation, performed by an “operation complete” interrupt) • Object Disk • Object Console – Simulates behavior of a character-oriented CRT device (one character at a time) – Methods: Console (constructor, connects to files / streams), PutChar, GetChar, CheckCharAvail -17- TDDB63 Lab lesson Nachos Processes and Threads Overview • Process: a user program in execution • Thread (Nachos): the kernel correspondent of a user process Thread Process 1 Thread 2 Thread 3 OS KERNEL -19- 7''% /DEOHVVRQ – Simulates behavior of a real disk (single platter, multiple tracks containing sectors, blocks uniquely identified by their sector number) – Methods: Disk (constructor), ReadRequest (read single sector), WriteRequest (write single sector), ComputeLatency (used to decide when to schedule an “I/O complete” interrupt when servicing a read or write request) 1 Process 2 Process 3 Test Testprograms programs TDDB63 Lab lesson -18- TDDB63 Lab lesson Nachos Processes and Threads: Overview • Process: – Single thread of control (executing the code) – Other objects (open file descriptors, etc.) – => program (instructions), data, state information (memory, registers, etc.) • Thread (Nachos): – Address space (memory allowed to reference: code, stack, heap, dynamically allocated memory) – Global variables are shared among all threads (=> synchronisation?, mutual exclusion?) -20- TDDB63 Lab lesson Lab1: Threads • Nachos threads are in one of four states – READY – RUNNING – BLOCKED – JUST_CREATED (temporary state) • The scheduler decides which thread to run next • Synchronization facilities are provided through semaphores Threads and Scheduling • Scheduler decides which thread to run next (invoked whenever the current thread gives up the CPU or an interrupt arrives) • Ready list (threads which are ready to run) • Nachos: unprioritized, round-robin fashion • Object Scheduler methods: – ReadyToRun(thread_object) -place the thread in ready list – FindNextToRun – Run TDDB63 Lab lesson -21- Thread switching • • • • Suspend current thread Save thread state (registers) Restore state of of thread to switch to => function Switch(oldThread, nextThread) (written in assembly language) TDDB63 Lab lesson -22- Thread Object • Thread Object methods: – – – – – – Thread (constructor) Fork (making thread executable) StackAllocate Yield (suspend and select next waiting one) Sleep (suspend) Finish (terminate) • Read documentation / source code -23- 7''% /DEOHVVRQ TDDB63 Lab lesson -24- TDDB63 Lab lesson Nachos Threads void ThreadFunction1(int which); void ThreadFunction2(int which); void ThreadTest() { Thread *t1 = new Thread(“first thread"); Thread *t2 = new Thread(“second thread"); t1->Fork(ThreadFunction1, 1); t2->Fork(ThreadFunction2, 2); ThreadFunction(1); } void ThreadFunction1(int which){ int num; for (num = 0; num < 5; num++) { printf("*** thread %d looped %d times\n", which, num); currentThread->Yield(); } } TDDB63 Lab lesson -25- Why Synchronization int num; void ThreadFunction1(int which); void ThreadFunction2(int which); void ThreadTest() { Thread *t1 = new Thread(“first thread"); Thread *t2 = new Thread(“second thread"); t1->Fork(ThreadFunction1, 1); t2->Fork(ThreadFunction2, 2); } -27- 7''% /DEOHVVRQ Nachos Threads (cont.) -26- TDDB63 Lab lesson Synchronisation and Mutual Exclusion • Mutual exclusion achieved by disabling / enabling interrupts • Synchronisation provided through semaphores • Object Semaphore methods: – Semaphore (constructor) – P (decrement semaphore’s counter, blocking caller if 0) – V (increment semaphore’s counter, releasing one thread if any are blocked) TDDB63 Lab lesson -28- TDDB63 Lab lesson Lab1: Semaphores • A semaphore is an integer variable, accessible only by the operations P and V (Claim, and Release) • P() - decrement the semaphore’s count, blocking the caller if count is zero. void Semaphore::P() { IntStatus oldLevel = interrupt->SetLevel(IntOff) ; while(value == 0) { queue->Append((void *)currentThread) ; currentThread->Sleep() ; } value = value - 1 ; (void) interrupt->SetLevel(oldLevel) ; }; Wait(S): while S <= 0 do no-op; S := S -1 ; Signal(S): S := S + 1 ; -29- Lab1: Semaphores - P() TDDB63 Lab lesson -30- Lab1: Semaphores - V() • V() - Increment the semaphore’s count, releasing one thread if any are blocked waiting on the count void Semaphore::V() { Thread *thread; IntStatus oldLevel = interrupt->SetLevel(IntOff) ; thread = (Thread *)queue->remove() ; if (thread != NULL) scheduler->ReadyToRun(thread) ; value = value + 1 ; (void) interrupt->SetLevel(oldLevel) ; }; -31- 7''% /DEOHVVRQ TDDB63 Lab lesson TDDB63 Lab lesson Locks • A binary semaphore • Checks that only the thread that acquired the lock can release it • Use the Semaphore class + additional stuff -32- TDDB63 Lab lesson Lab1: Lock class Lock { public: Lock(char* debugName); ~Lock(); void Acquire(); // atomic void Release(); // atomic bool isHeldbyCurrentThread(); private: char *name; // some variables you need }; -33- Condition Variables • Semaphores and Locks are not very efficient when dealing with multiple resources P1 Lock1->Acquire(); Lock2->Acquire(); … Lock2->Release; Lock1->Release(); P3 Lock2->Acquire(); Lock3->Acquire(); … Lock3->Release(); Lock2->Release(); Why hold a lock if you can not use it ? TDDB63 Lab lesson -34- Condition Variables (Wait) • Wait TDDB63 Lab lesson Condition Variables (Signal) • Signal – Release the lock – Add the thread to a queue of threads waiting on this condition – Go to sleep – Acquire the lock -35- 7''% /DEOHVVRQ P2 Lock3->Acquire(); Lock1->Acquire(); … Lock1->Release; Lock3->Release(); TDDB63 Lab lesson – Take one thread from the list – Run it (scheduler->ReadyToRun(that thread)) • Broadcast – Wake up all the threads and let them compete for the lock -36- TDDB63 Lab lesson Readers&Writers • Given a file • Two kinds of processes can access that file: – Readers – Writers • Correct operation: Readers&Writers • • • • • int counter_for_read; Lock *lock_for_counter; Lock *lock_for_readers_writers; Condition *c_counter; Condition *c_write; – several readers can read simultaneously – Only one writer is allowed to access the file TDDB63 Lab lesson -37- -38- Readers&Writers Reader() { wait(c_counter); counter_for_read++; if (counter_for_read==1) wait(c_write); signal(c_counter); …..do the reading…. wait(c_counter); counter_for_read--; if (counter_for_read==0) signal(c_write); signal(c_counter); } -39- 7''% /DEOHVVRQ TDDB63 Lab lesson Readers&Writers Writer() { wait(c_write); …..do the writing…. signal(c_write); } TDDB63 Lab lesson -40- TDDB63 Lab lesson Lab 1: Preparation • Read and understand the partial thread system (nachos-3.4/code/threads) • Remember: module add prog/gcc/2.8.1 • Run the test program in the debugger and follow the state of each thread object • Compile in the code/threads directory TDDB63 Lab lesson -41- Lab1: Condition class Condition { public: Condition (char * debugName); ~Condition(); void Wait(Lock *conditionLock); void Signal(Lock *conditionLock); void Broadcast(Lock *conditionLock); private: char *name; // some variables you need }; -43- 7''% /DEOHVVRQ Lab1: Assignment 1 • Implement locks and conditions - when used together provides the same functionality as monitors • Write code for the Lock and Condition classes (in the file ../code/threads/sync.cc) – Interfaces (class definition) for Lock and Condition are already defined (in ../code/threads/sync.h) – No changes to the interfaces should be done. Only needed variables should be added to the classes – NB: It should not take too much code for you to implement all functionality -42- TDDB63 Lab lesson Lab1: Assignment 2 • Test your implementation – Write a class BoundedBuffer (in the file code/threads/threadtest.cc) and use it for producer/consumer communication. (Silberschatz, p. 172) – Don’t forget border conditions: empty buffer, full buffer – Try several producers and/or consumers TDDB63 Lab lesson -44- TDDB63 Lab lesson BoundedBuffer class BoundedBuffer { public: BoundedBuffer(int bufsize); ~BoundedBuffer(); int Read(); void Write(int value); private: // some variables you need }; -45- 7''% /DEOHVVRQ TDDB63 Lab lesson