diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 9fc91d06cd..f491bc16f7 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.104 2001/07/06 21:04:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.105 2001/09/04 02:26:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -506,16 +506,14 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable, SPINLOCK spinlock = lockctl->masterLock; PROC_QUEUE *waitQueue = &(lock->waitProcs); int myHeldLocks = MyProc->heldLocks; + bool early_deadlock = false; PROC *proc; int i; - #ifndef __BEOS__ struct itimerval timeval, dummy; - #else bigtime_t time_interval; - #endif /* @@ -535,7 +533,6 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable, * immediately. This is the same as the test for immediate grant in * LockAcquire, except we are only considering the part of the wait * queue before my insertion point. - * */ if (myHeldLocks != 0) { @@ -550,9 +547,14 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable, /* Must I wait for him ? */ if (lockctl->conflictTab[lockmode] & proc->heldLocks) { - /* Yes, can report deadlock failure immediately */ - MyProc->errType = STATUS_ERROR; - return STATUS_ERROR; + /* + * Yes, so we have a deadlock. Easiest way to clean up + * correctly is to call RemoveFromWaitQueue(), but we + * can't do that until we are *on* the wait queue. + * So, set a flag to check below, and break out of loop. + */ + early_deadlock = true; + break; } /* I must go before this waiter. Check special case. */ if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 && @@ -600,7 +602,19 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable, MyProc->waitHolder = holder; MyProc->waitLockMode = lockmode; - MyProc->errType = STATUS_OK;/* initialize result for success */ + MyProc->errType = STATUS_OK; /* initialize result for success */ + + /* + * If we detected deadlock, give up without waiting. This must agree + * with HandleDeadLock's recovery code, except that we shouldn't release + * the semaphore since we haven't tried to lock it yet. + */ + if (early_deadlock) + { + RemoveFromWaitQueue(MyProc); + MyProc->errType = STATUS_ERROR; + return STATUS_ERROR; + } /* mark that we are waiting for a lock */ waitingForLock = true; @@ -693,6 +707,10 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable, * * Also remove the process from the wait queue and set its links invalid. * RETURN: the next process in the wait queue. + * + * 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. */ PROC * ProcWakeup(PROC *proc, int errType)