//--------------------------------------------------------------------------- // CondHandleWait // // This function makes the calling process block on the condition variable // till either ConditionHandleSignal or ConditionHandleBroadcast is // received. The process calling CondHandleWait must have acquired the // lock associated with the condition variable (the lock that was passed // to CondCreate. This implies the lock handle needs to be stored // somewhere. hint! hint!) for this function to // succeed. If the calling process has not acquired the lock, it does not // block on the condition variable, but a value of 1 is returned // indicating that the call was not successful. Return value of 0 implies // that the call was successful. // // This function should be written in such a way that the calling process // should release the lock associated with this condition variable before // going to sleep, so that the process that intends to signal this // process could acquire the lock for that purpose. After waking up, the // blocked process should acquire (i.e. wait on) the lock associated with // the condition variable. In other words, this process does not // "actually" wake up until the process calling CondHandleSignal or // CondHandleBroadcast releases the lock explicitly. //--------------------------------------------------------------------------- int CondWait(Cond *c) { Link *l; int intrval; if (!c) return SYNC_FAIL; // Conds are atomic intrval = DisableIntrs (); dbprintf ('I', "CondWait: Old interrupt value was 0x%x.\n", intrval); // Check to see if the current process owns the lock if (c->lock->pid != GetCurrentPid()) { dbprintf('s', "CondWait: Proc %d does not own cond %d\n", GetCurrentPid(), (int)(c-conds)); RestoreIntrs(intrval); return SYNC_FAIL; } dbprintf ('s', "CondWait: Proc %d waiting on cond %d. Putting to sleep.\n", GetCurrentPid(), (int)(c-conds)); if ((l = AQueueAllocLink ((void *)currentPCB)) == NULL) { printf("FATAL ERROR: could not allocate link for cond queue in CondWait!\n"); exitsim(); } if (AQueueInsertLast (&c->waiting, l) != QUEUE_SUCCESS) { printf("FATAL ERROR: could not insert new link into cond waiting queue in CondWait!\n"); exitsim(); } // Release the lock before going to sleep LockRelease(c->lock); RestoreIntrs(intrval); // Don't want interrupts disabled while we sleep ProcessSleep(); // Immediately acquire the lock upon waking LockAcquire(c->lock); return SYNC_SUCCESS; }
//---------------------------------------------------------------------- // // SemWait // // Wait on a semaphore. As described in Section 6.4 of _OSC_, // we decrement the counter and suspend the process if the // semaphore's value is less than 0. To ensure atomicity, // interrupts are disabled for the entire operation, but must be // turned on before going to sleep. // //---------------------------------------------------------------------- int SemWait (Sem *sem) { Link *l; int intrval; if (!sem) return SYNC_FAIL; intrval = DisableIntrs (); dbprintf ('I', "SemWait: Old interrupt value was 0x%x.\n", intrval); dbprintf ('s', "SemWait: Proc %d waiting on sem %d, count=%d.\n", GetCurrentPid(), (int)(sem-sems), sem->count); if (sem->count <= 0) { dbprintf('s', "SemWait: putting process %d to sleep\n", GetCurrentPid()); if ((l = AQueueAllocLink ((void *)currentPCB)) == NULL) { printf("FATAL ERROR: could not allocate link for semaphore queue in SemWait!\n"); exitsim(); } if (AQueueInsertLast (&sem->waiting, l) != QUEUE_SUCCESS) { printf("FATAL ERROR: could not insert new link into semaphore waiting queue in SemWait!\n"); exitsim(); } ProcessSleep(); // Don't decrement couter here because that's handled in SemSignal for us } else { sem->count--; // Decrement internal counter dbprintf('s', "SemWait: Proc %d granted permission to continue by sem %d\n", GetCurrentPid(), (int)(sem-sems)); } RestoreIntrs (intrval); return SYNC_SUCCESS; }
//---------------------------------------------------------------------- // // SemWait // // Wait on a semaphore. As described in Section 6.4 of _OSC_, // we decrement the counter and suspend the process if the // semaphore's value is less than 0. To ensure atomicity, // interrupts are disabled for the entire operation. Note that, // if the process is put to sleep, interrupts will be OFF when // it returns from sleep. Thus, we enable interrupts at the end of // the routine. // //---------------------------------------------------------------------- void SemWait (Sem *sem) { Link *l; int intrval; intrval = DisableIntrs (); dbprintf ('I', "Old interrupt value was 0x%x.\n", intrval); dbprintf ('s', "Proc 0x%x waiting on sem 0x%x, count=%d.\n", currentPCB, sem, sem->count); sem->count -= 1; if (sem->count < 0) { l = QueueAllocLink (); QueueLinkInit (l, (void *)currentPCB); dbprintf ('s', "Suspending current proc (0x%x).\n", currentPCB); QueueInsertLast (&sem->waiting, l); ProcessSleep (); } RestoreIntrs (intrval); }
//--------------------------------------------------------------------------- // LockHandleAcquire // // This routine acquires a lock given its handle. The handle must be a // valid handle for this routine to succeed. In that case this routine // returns SYNC_FAIL. Otherwise the routine returns SYNC_SUCCESS. // // Your implementation should be such that if a process that already owns // the lock calls LockHandleAcquire for that lock, it should not block. //--------------------------------------------------------------------------- int LockAcquire(Lock *k) { Link *l; int intrval; if (!k) return SYNC_FAIL; // Locks are atomic intrval = DisableIntrs (); dbprintf ('I', "LockAcquire: Old interrupt value was 0x%x.\n", intrval); // Check to see if the current process owns the lock if (k->pid == GetCurrentPid()) { dbprintf('s', "LockAcquire: Proc %d already owns lock %d\n", GetCurrentPid(), (int)(k-locks)); RestoreIntrs(intrval); return SYNC_SUCCESS; } dbprintf ('s', "LockAcquire: Proc %d asking for lock %d.\n", GetCurrentPid(), (int)(k-locks)); if (k->pid >= 0) { // Lock is already in use by another process dbprintf('s', "LockAcquire: putting process %d to sleep\n", GetCurrentPid()); if ((l = AQueueAllocLink ((void *)currentPCB)) == NULL) { printf("FATAL ERROR: could not allocate link for lock queue in LockAcquire!\n"); exitsim(); } if (AQueueInsertLast (&k->waiting, l) != QUEUE_SUCCESS) { printf("FATAL ERROR: could not insert new link into lock waiting queue in LockAcquire!\n"); exitsim(); } ProcessSleep(); } else { dbprintf('s', "LockAcquire: lock is available, assigning to proc %d\n", GetCurrentPid()); k->pid = GetCurrentPid(); } RestoreIntrs(intrval); return SYNC_SUCCESS; }