Main Page | Alphabetical List | Class List | File List | Class Members | File Members

synch.cc

Go to the documentation of this file.
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::Suspend assumes that interrupts are disabled 00061 // when it is called. 00062 //---------------------------------------------------------------------- 00063 00064 void Semaphore::P() 00065 { 00066 IntStatus oldLevel = interrupt->SetLevel(IntOff); // disable interrupts 00067 00068 while (value == 0) 00069 { // semaphore not available 00070 queue->Append((void *)currentThread); // so go to sleep 00071 DEBUG('t', "Suspendp %s\n", currentThread->getName()); 00072 currentThread->Suspend(); 00073 } 00074 value--; // semaphore available, 00075 // consume its value 00076 00077 (void) interrupt->SetLevel(oldLevel); // re-enable interrupts 00078 } 00079 00080 //---------------------------------------------------------------------- 00081 // Semaphore::V 00082 // Increment semaphore value, waking up a waiter if necessary. 00083 // As with P(), this operation must be atomic, so we need to disable 00084 // interrupts. Scheduler::ReadyToRun() assumes that threads 00085 // are disabled when it is called. 00086 //---------------------------------------------------------------------- 00087 00088 void 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 { 00096 scheduler->ReadyToRun(thread); 00097 DEBUG('t', "Wakeup %s\n", thread->getName()); 00098 } 00099 value++; 00100 (void) interrupt->SetLevel(oldLevel); 00101 } 00102 00103 // Dummy functions -- so we can compile our later assignments 00104 // Note -- without a correct implementation of Condition::Wait(), 00105 // the test case in the network assignment won't work! 00106 Lock::Lock(char* debugName) {} 00107 Lock::~Lock() {} 00108 void Lock::Acquire() {} 00109 void Lock::Release() {} 00110 00111 Condition::Condition(char* debugName) { } 00112 Condition::~Condition() { } 00113 void Condition::Wait(Lock* conditionLock) { ASSERT(FALSE); } 00114 void Condition::Signal(Lock* conditionLock) { } 00115 void Condition::Broadcast(Lock* conditionLock) { } 00116 00117 00118 00119 00120

Generated on Thu Sep 16 12:33:45 2004 for NachOS by doxygen 1.3.8