//--------------------------------------------------------------------------- // LockHandleRelease // // This procedure releases the unique lock described by the handle. It // first checks whether the lock is a valid lock. If not, it returns SYNC_FAIL. // If the lock is a valid lock, it should check whether the calling // process actually holds the lock. If not it returns SYNC_FAIL. Otherwise it // releases the lock, and returns SYNC_SUCCESS. //--------------------------------------------------------------------------- int LockRelease(Lock *k) { Link *l; int intrs; PCB *pcb; if (!k) return SYNC_FAIL; intrs = DisableIntrs (); dbprintf ('s', "LockRelease: Proc %d releasing lock %d.\n", GetCurrentPid(), (int)(k-locks)); if (k->pid != GetCurrentPid()) { dbprintf('s', "LockRelease: Proc %d does not own lock %d.\n", GetCurrentPid(), (int)(k-locks)); return SYNC_FAIL; } k->pid = -1; if (!AQueueEmpty(&k->waiting)) { // there is a process to wake up l = AQueueFirst(&k->waiting); pcb = (PCB *)AQueueObject(l); if (AQueueRemove(&l) != QUEUE_SUCCESS) { printf("FATAL ERROR: could not remove link from lock queue in LockRelease!\n"); exitsim(); } dbprintf ('s', "LockRelease: Waking up PID %d, assigning lock.\n", (int)(GetPidFromAddress(pcb))); k->pid = GetPidFromAddress(pcb); ProcessWakeup (pcb); } RestoreIntrs (intrs); return SYNC_SUCCESS; }
//--------------------------------------------------------------------------- // CondHandleSignal // // This call wakes up exactly one process waiting on the condition // variable, if at least one is waiting. If there are no processes // waiting on the condition variable, it does nothing. In either case, // the calling process must have acquired the lock associated with // condition variable for this call to succeed, in which case it returns // 0. If the calling process does not own the lock, it returns 1, // indicating that the call was not successful. This function should be // written in such a way that the calling process should retain the // acquired lock even after the call completion (in other words, it // should not release the lock it has already acquired before the call). // // Note that the process woken up by this call tries to acquire the lock // associated with the condition variable as soon as it wakes up. Thus, // for such a process to run, the process invoking CondHandleSignal // must explicitly release the lock after the call is complete. //--------------------------------------------------------------------------- int CondSignal(Cond *c) { Link *l; int intrs; PCB *pcb; if (!c) return SYNC_FAIL; intrs = DisableIntrs (); dbprintf ('s', "CondSignal: Proc %d signalling cond %d.\n", GetCurrentPid(), (int)(c-conds)); if (c->lock->pid != GetCurrentPid()) { dbprintf('s', "CondSignal: Proc %d does not own cond %d.\n", GetCurrentPid(), (int)(c-conds)); return SYNC_FAIL; } if (!AQueueEmpty(&c->waiting)) { // there is a process to wake up l = AQueueFirst(&c->waiting); pcb = (PCB *)AQueueObject(l); if (AQueueRemove(&l) != QUEUE_SUCCESS) { printf("FATAL ERROR: could not remove link from cond queue in CondSignal!\n"); exitsim(); } dbprintf ('s', "CondSignal: Waking up PID %d, it still needs to acquire lock.\n", GetPidFromAddress(pcb)); ProcessWakeup (pcb); } else { dbprintf('s', "CondSignal: Proc %d signalled, but no processes were waiting.\n", GetCurrentPid()); } RestoreIntrs (intrs); return SYNC_SUCCESS; }
//---------------------------------------------------------------------- // // SemSignal // // Signal on a semaphore. Again, details are in Section 6.4 of // _OSC_. // //---------------------------------------------------------------------- int SemSignal (Sem *sem) { Link *l; int intrs; PCB *pcb; if (!sem) return SYNC_FAIL; intrs = DisableIntrs (); dbprintf ('s', "SemSignal: Process %d Signalling on sem %d, count=%d.\n", GetCurrentPid(), (int)(sem-sems), sem->count); // Increment internal counter before checking value sem->count++; if (sem->count > 0) { // check if there is a process to wake up if (!AQueueEmpty(&sem->waiting)) { // there is a process to wake up l = AQueueFirst(&sem->waiting); pcb = (PCB *)AQueueObject(l); if (AQueueRemove(&l) != QUEUE_SUCCESS) { printf("FATAL ERROR: could not remove link from semaphore queue in SemSignal!\n"); exitsim(); } dbprintf ('s', "SemSignal: Waking up PID %d.\n", (int)(GetPidFromAddress(pcb))); ProcessWakeup (pcb); // Decrement counter on behalf of woken up PCB sem->count--; } } RestoreIntrs (intrs); return SYNC_SUCCESS; }
//---------------------------------------------------------------------- // // SemSignal // // Signal on a semaphore. Again, details are in Section 6.4 of // _OSC_. // //---------------------------------------------------------------------- void SemSignal (Sem *sem) { Link *l; int intrs; intrs = DisableIntrs (); dbprintf ('s', "Signalling on sem 0x%x, count=%d.\n", sem, sem->count); sem->count += 1; if (sem->count <= 0) { l = QueueFirst (&sem->waiting); QueueRemove (l); dbprintf ('s', "Waking up PCB 0x%x.\n", l->object); ProcessWakeup ((PCB *)(l->object)); QueueFreeLink (l); } RestoreIntrs (intrs); }