Main Page   Compound List   File List   Compound 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::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) { }

Generated on Mon Feb 10 09:54:47 2003 for nachos by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002
The University of Southern California does not screen or control the content on this website and thus does not guarantee the accuracy, integrity, or quality of such content. All content on this website is provided by and is the sole responsibility of the person from which such content originated, and such content does not necessarily reflect the opinions of the University administration or the Board of Trustees