/* * ProcWakeup -- wake up a process by releasing its private___ semaphore. * * Also remove the process from the wait queue and set its links invalid. * RETURN: the next process in the wait queue. * * The appropriate lock partition lock must be held by caller. * * XXX: presently, this code is only used for the "success" case, and only * works correctly for that case. To clean up in failure case, would need * to twiddle the lock's request counts too --- see RemoveFromWaitQueue. * Hence, in practice the waitStatus parameter must be STATUS_OK. */ PGPROC * ProcWakeup(PGPROC *proc, int waitStatus) { PGPROC *retProc; /* Proc should be sleeping ... */ if (proc->links.prev == NULL || proc->links.next == NULL) return NULL; Assert(proc->waitStatus == STATUS_WAITING); /* Save next process before we zap the list link */ retProc = (PGPROC *) proc->links.next; /* Remove process from wait queue */ SHMQueueDelete(&(proc->links)); (proc->waitLock->waitProcs.size)--; /* Clean up process' state and pass it the ok/fail signal */ proc->waitLock = NULL; proc->waitProcLock = NULL; proc->waitStatus = waitStatus; /* And awaken it */ SetLatch(&proc->procLatch); return retProc; }
/* * Acquire SyncRepLock and cancel any wait currently in progress. */ static void SyncRepCancelWait(void) { LWLockAcquire(SyncRepLock, LW_EXCLUSIVE); if (!SHMQueueIsDetached(&(MyProc->syncRepLinks))) SHMQueueDelete(&(MyProc->syncRepLinks)); MyProc->syncRepState = SYNC_REP_NOT_WAITING; LWLockRelease(SyncRepLock); }
void SyncRepCleanupAtProcExit(void) { if (!SHMQueueIsDetached(&(MyProc->syncRepLinks))) { LWLockAcquire(SyncRepLock, LW_EXCLUSIVE); SHMQueueDelete(&(MyProc->syncRepLinks)); LWLockRelease(SyncRepLock); } }
void SyncRepCleanupAtProcExit(int code, Datum arg) { if (!SHMQueueIsDetached(&(MyProc->syncRepLinks))) { LWLockAcquire(SyncRepLock, LW_EXCLUSIVE); SHMQueueDelete(&(MyProc->syncRepLinks)); LWLockRelease(SyncRepLock); } DisownLatch(&MyProc->waitLatch); }
/* * ProcKill() -- Destroy the per-proc data structure for * this process. Release any of its held spin locks. */ static void ProcKill(int exitStatus, int pid) { PROC *proc; SHMEM_OFFSET location; /* -------------------- * If this is a FATAL exit the postmaster will have to kill all the * existing backends and reinitialize shared memory. So all we don't * need to do anything here. * -------------------- */ if (exitStatus != 0) return; if (! pid) { pid = getpid(); } ShmemPIDLookup(pid,&location); if (location == INVALID_OFFSET) return; proc = (PROC *) MAKE_PTR(location); if (proc != MyProc) { Assert( pid != getpid() ); } else MyProc = NULL; /* --------------- * Assume one lock table. * --------------- */ ProcReleaseSpins(proc); LockReleaseAll(1,&proc->lockQueue); /* ---------------- * get off the wait queue * ---------------- */ LockLockTable(); if (proc->links.next != INVALID_OFFSET) { Assert(proc->waitLock->waitProcs.size > 0); SHMQueueDelete(&(proc->links)); --proc->waitLock->waitProcs.size; } SHMQueueElemInit(&(proc->links)); UnlockLockTable(); return; }
/* * ProcWakeup -- wake up a process by releasing its private semaphore. * * remove the process from the wait queue and set its links invalid. * RETURN: the next process in the wait queue. */ PROC * ProcWakeup(PROC *proc, int errType) { PROC *retProc; /* assume that spinlock has been acquired */ if (proc->links.prev == INVALID_OFFSET || proc->links.next == INVALID_OFFSET) return((PROC *) NULL); retProc = (PROC *) MAKE_PTR(proc->links.prev); /* you have to update waitLock->waitProcs.size yourself */ SHMQueueDelete(&(proc->links)); SHMQueueElemInit(&(proc->links)); proc->errType = errType; IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock); return retProc; }
/* -------------------- * We only get to this routine if we got SIGALRM after DEADLOCK_TIMEOUT * while waiting for a lock to be released by some other process. After * the one minute deadline we assume we have a deadlock and must abort * this transaction. We must also indicate that I'm no longer waiting * on a lock so that other processes don't try to wake me up and screw * up my semaphore. * -------------------- */ void HandleDeadLock(int sig) { LOCK *lock; int size; LockLockTable(); /* --------------------- * Check to see if we've been awoken by anyone in the interim. * * If we have we can return and resume our transaction -- happy day. * Before we are awoken the process releasing the lock grants it to * us so we know that we don't have to wait anymore. * * Damn these names are LONG! -mer * --------------------- */ if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) == IpcSemaphoreDefaultStartValue) { UnlockLockTable(); return; } /* * you would think this would be unnecessary, but... * * this also means we've been removed already. in some ports * (e.g., sparc and aix) the semop(2) implementation is such that * we can actually end up in this handler after someone has removed * us from the queue and bopped the semaphore *but the test above * fails to detect the semaphore update* (presumably something weird * having to do with the order in which the semaphore wakeup signal * and SIGALRM get handled). */ if (MyProc->links.prev == INVALID_OFFSET || MyProc->links.next == INVALID_OFFSET) { UnlockLockTable(); return; } lock = MyProc->waitLock; size = lock->waitProcs.size; /* so we can look at this in the core */ /* ------------------------ * Get this process off the lock's wait queue * ------------------------ */ Assert(lock->waitProcs.size > 0); --lock->waitProcs.size; SHMQueueDelete(&(MyProc->links)); SHMQueueElemInit(&(MyProc->links)); /* ------------------ * Unlock my semaphore so that the count is right for next time. * I was awoken by a signal, not by someone unlocking my semaphore. * ------------------ */ IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock); /* ------------- * Set MyProc->errType to STATUS_ERROR so that we abort after * returning from this handler. * ------------- */ MyProc->errType = STATUS_ERROR; /* * if this doesn't follow the IpcSemaphoreUnlock then we get lock * table corruption ("LockReplace: xid table corrupted") due to * race conditions. i don't claim to understand this... */ UnlockLockTable(); elog(NOTICE, "Timeout -- possible deadlock"); return; }