/* * ProcLockWakeup -- routine for waking up processes when a lock is * released (or a prior waiter is aborted). Scan all waiters * for lock, waken any that are no longer blocked. * * The appropriate lock partition lock must be held by caller. */ void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock) { PROC_QUEUE *waitQueue = &(lock->waitProcs); int queue_size = waitQueue->size; PGPROC *proc; LOCKMASK aheadRequests = 0; Assert(queue_size >= 0); if (queue_size == 0) return; proc = (PGPROC *) waitQueue->links.next; while (queue_size-- > 0) { LOCKMODE lockmode = proc->waitLockMode; /* * Waken if (a) doesn't conflict with requests of earlier waiters, and * (b) doesn't conflict with already-held locks. */ if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 && LockCheckConflicts(lockMethodTable, lockmode, lock, proc->waitProcLock, proc) == STATUS_OK) { /* OK to waken */ GrantLock(lock, proc->waitProcLock, lockmode); proc = ProcWakeup(proc, STATUS_OK); /* * ProcWakeup removes proc from the lock's waiting process queue * and returns the next proc in chain; don't use proc's next-link, * because it's been cleared. */ } else { /* * Cannot wake this guy. Remember his request for later checks. */ aheadRequests |= LOCKBIT_ON(lockmode); proc = (PGPROC *) proc->links.next; } } Assert(waitQueue->size >= 0); }
/* * ProcLockWakeup -- routine for waking up processes when a lock is * released. */ int ProcLockWakeup(PROC_QUEUE *queue, char *ltable, char *lock) { PROC *proc; int count; if (! queue->size) return(STATUS_NOT_FOUND); proc = (PROC *) MAKE_PTR(queue->links.prev); count = 0; while ((LockResolveConflicts ((LOCKTAB *) ltable, (LOCK *) lock, proc->token, proc->xid) == STATUS_OK)) { /* there was a waiting process, grant it the lock before waking it * up. This will prevent another process from seizing the lock * between the time we release the lock master (spinlock) and * the time that the awoken process begins executing again. */ GrantLock((LOCK *) lock, proc->token); queue->size--; /* * ProcWakeup removes proc from the lock waiting process queue and * returns the next proc in chain. If a writer just dropped * its lock and there are several waiting readers, wake them all up. */ proc = ProcWakeup(proc, NO_ERROR); count++; if (!proc || queue->size == 0) break; } if (count) return(STATUS_OK); else /* Something is still blocking us. May have deadlocked. */ return(STATUS_NOT_FOUND); }