00001 // synch.cc 00002 // Routines for synchronizing threads. Three kinds of 00003 // synchronization routines are defined here: semaphores, locks 00004 // and condition variables (the implementation of the last two 00005 // are left to the reader). 00006 // 00007 // Any implementation of a synchronization routine needs some 00008 // primitive atomic operation. We assume Nachos is running on 00009 // a uniprocessor, and thus atomicity can be provided by 00010 // turning off interrupts. While interrupts are disabled, no 00011 // context switch can occur, and thus the current thread is guaranteed 00012 // to hold the CPU throughout, until interrupts are reenabled. 00013 // 00014 // Because some of these routines might be called with interrupts 00015 // already disabled (Semaphore::V for one), instead of turning 00016 // on interrupts at the end of the atomic operation, we always simply 00017 // re-set the interrupt state back to its original value (whether 00018 // that be disabled or enabled). 00019 // 00020 // Copyright (c) 1992-1993 The Regents of the University of California. 00021 // All rights reserved. See copyright.h for copyright notice and limitation 00022 // of liability and disclaimer of warranty provisions. 00023 00024 #include "copyright.h" 00025 #include "synch.h" 00026 #include "system.h" 00027 00028 //---------------------------------------------------------------------- 00029 // Semaphore::Semaphore 00030 // Initialize a semaphore, so that it can be used for synchronization. 00031 // 00032 // "debugName" is an arbitrary name, useful for debugging. 00033 // "initialValue" is the initial value of the semaphore. 00034 //---------------------------------------------------------------------- 00035 00036 Semaphore::Semaphore(char* debugName, int initialValue) 00037 { 00038 name = debugName; 00039 value = initialValue; 00040 queue = new List; 00041 } 00042 00043 //---------------------------------------------------------------------- 00044 // Semaphore::Semaphore 00045 // De-allocate semaphore, when no longer needed. Assume no one 00046 // is still waiting on the semaphore! 00047 //---------------------------------------------------------------------- 00048 00049 Semaphore::~Semaphore() 00050 { 00051 delete queue; 00052 } 00053 00054 //---------------------------------------------------------------------- 00055 // Semaphore::P 00056 // Wait until semaphore value > 0, then decrement. Checking the 00057 // value and decrementing must be done atomically, so we 00058 // need to disable interrupts before checking the value. 00059 // 00060 // Note that Thread::Sleep assumes that interrupts are disabled 00061 // when it is called. 00062 //---------------------------------------------------------------------- 00063 00064 void 00065 Semaphore::P() 00066 { 00067 IntStatus oldLevel = interrupt->SetLevel(IntOff); // disable interrupts 00068 00069 while (value == 0) { // semaphore not available 00070 queue->Append((void *)currentThread); // so go to sleep 00071 currentThread->Sleep(); 00072 } 00073 value--; // semaphore available, 00074 // consume its value 00075 00076 (void) interrupt->SetLevel(oldLevel); // re-enable interrupts 00077 } 00078 00079 //---------------------------------------------------------------------- 00080 // Semaphore::V 00081 // Increment semaphore value, waking up a waiter if necessary. 00082 // As with P(), this operation must be atomic, so we need to disable 00083 // interrupts. Scheduler::ReadyToRun() assumes that threads 00084 // are disabled when it is called. 00085 //---------------------------------------------------------------------- 00086 00087 void 00088 Semaphore::V() 00089 { 00090 Thread *thread; 00091 IntStatus oldLevel = interrupt->SetLevel(IntOff); 00092 00093 thread = (Thread *)queue->Remove(); 00094 if (thread != NULL) // make thread ready, consuming the V immediately 00095 scheduler->ReadyToRun(thread); 00096 value++; 00097 (void) interrupt->SetLevel(oldLevel); 00098 } 00099 00100 // Dummy functions -- so we can compile our later assignments 00101 // Note -- without a correct implementation of Condition::Wait(), 00102 // the test case in the network assignment won't work! 00103 Lock::Lock(char* debugName) {} 00104 Lock::~Lock() {} 00105 void Lock::Acquire() {} 00106 void Lock::Release() {} 00107 00108 Condition::Condition(char* debugName) { } 00109 Condition::~Condition() { } 00110 void Condition::Wait(Lock* conditionLock) { ASSERT(FALSE); } 00111 void Condition::Signal(Lock* conditionLock) { } 00112 void Condition::Broadcast(Lock* conditionLock) { }
1.2.14 written by Dimitri van Heesch,
© 1997-2002