X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Fstorage%2Flmgr%2Fproc.c;h=e68d96d772951f89f4aaf1093e92b152ca0eed26;hb=416bbbffa3b0ffc2fde3893ea0928206b10afb0a;hp=01097fcd2fe642ebada361535a2b3b6cd020fce8;hpb=5c25d60244d3a4b458ba55d4f1e50386edb26507;p=postgresql diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 01097fcd2f..e68d96d772 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.67 2000/01/26 05:57:02 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.80 2000/10/02 19:42:48 petere Exp $ * *------------------------------------------------------------------------- */ @@ -47,8 +47,10 @@ * This is so that we can support more backends. (system-wide semaphore * sets run out pretty fast.) -ay 4/95 * - * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.67 2000/01/26 05:57:02 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.80 2000/10/02 19:42:48 petere Exp $ */ +#include "postgres.h" + #include #include #include @@ -59,23 +61,19 @@ #include #endif -#include "postgres.h" #include "miscadmin.h" -#include "libpq/pqsignal.h" -#include "storage/ipc.h" /* In Ultrix and QNX, sem.h must be included after ipc.h */ #include -#include "storage/lmgr.h" #include "storage/proc.h" -#include "utils/trace.h" -void HandleDeadLock(SIGNAL_ARGS); +void HandleDeadLock(SIGNAL_ARGS); static void ProcFreeAllSemaphores(void); +static bool GetOffWaitqueue(PROC *); -#define DeadlockCheckTimer pg_options[OPT_DEADLOCKTIMEOUT] +int DeadlockTimeout = 1000; /* -------------------- * Spin lock for manipulating the shared process data structure: @@ -122,7 +120,7 @@ InitProcGlobal(IPCKey key, int maxBackends) /* attach to the free list */ ProcGlobal = (PROC_HDR *) - ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found); + ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found); /* -------------------- * We're the first - initialize. @@ -143,7 +141,7 @@ InitProcGlobal(IPCKey key, int maxBackends) * Arrange to delete semas on exit --- set this up now so that we * will clean up if pre-allocation fails... */ - on_shmem_exit(ProcFreeAllSemaphores, NULL); + on_shmem_exit(ProcFreeAllSemaphores, 0); /* * Pre-create the semaphores for the first maxBackends processes, @@ -188,7 +186,7 @@ InitProcess(IPCKey key) /* attach to the free list */ ProcGlobal = (PROC_HDR *) - ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found); + ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found); if (!found) { /* this should not happen. InitProcGlobal() is called before this. */ @@ -221,7 +219,7 @@ InitProcess(IPCKey key) * cleanup dead processes). */ - MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC)); + MyProc = (PROC *) ShmemAlloc(sizeof(PROC)); if (!MyProc) { SpinRelease(ProcStructLock); @@ -309,7 +307,42 @@ InitProcess(IPCKey key) MyProc->errType = NO_ERROR; SHMQueueElemInit(&(MyProc->links)); - on_shmem_exit(ProcKill, (caddr_t) MyProcPid); + on_shmem_exit(ProcKill, (Datum) MyProcPid); +} + +/* ----------------------- + * get off the wait queue + * ----------------------- + */ +static bool +GetOffWaitqueue(PROC *proc) +{ + bool getoffed = false; + + LockLockTable(); + if (proc->links.next != INVALID_OFFSET) + { + int lockmode = proc->token; + LOCK *waitLock = proc->waitLock; + + Assert(waitLock); + Assert(waitLock->waitProcs.size > 0); + SHMQueueDelete(&(proc->links)); + --waitLock->waitProcs.size; + Assert(waitLock->nHolding > 0); + Assert(waitLock->nHolding > proc->waitLock->nActive); + --waitLock->nHolding; + Assert(waitLock->holders[lockmode] > 0); + --waitLock->holders[lockmode]; + if (waitLock->activeHolders[lockmode] == waitLock->holders[lockmode]) + waitLock->waitMask &= ~(1 << lockmode); + ProcLockWakeup(&(waitLock->waitProcs), LOCK_LOCKMETHOD(*waitLock), waitLock); + getoffed = true; + } + SHMQueueElemInit(&(proc->links)); + UnlockLockTable(); + + return getoffed; } /* @@ -322,6 +355,7 @@ ProcReleaseLocks() if (!MyProc) return; LockReleaseAll(1, &MyProc->lockQueue); + GetOffWaitqueue(MyProc); } /* @@ -405,15 +439,7 @@ ProcKill(int exitStatus, int pid) * 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(); + GetOffWaitqueue(proc); return; } @@ -435,7 +461,7 @@ ProcQueueAlloc(char *name) { bool found; PROC_QUEUE *queue = (PROC_QUEUE *) - ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found); + ShmemInitStruct(name, sizeof(PROC_QUEUE), &found); if (!queue) return NULL; @@ -457,6 +483,50 @@ ProcQueueInit(PROC_QUEUE *queue) } +/* + * Handling cancel request while waiting for lock + * + */ +static bool lockWaiting = false; +void +SetWaitingForLock(bool waiting) +{ + if (waiting == lockWaiting) + return; + lockWaiting = waiting; + if (lockWaiting) + { + /* The lock was already released ? */ + if (MyProc->links.next == INVALID_OFFSET) + { + lockWaiting = false; + return; + } + if (QueryCancel) /* cancel request pending */ + { + if (GetOffWaitqueue(MyProc)) + { + lockWaiting = false; + elog(ERROR, "Query cancel requested while waiting lock"); + } + } + } +} +void +LockWaitCancel(void) +{ + struct itimerval timeval, + dummy; + + if (!lockWaiting) + return; + lockWaiting = false; + /* Deadlock timer off */ + MemSet(&timeval, 0, sizeof(struct itimerval)); + setitimer(ITIMER_REAL, &timeval, &dummy); + if (GetOffWaitqueue(MyProc)) + elog(ERROR, "Query cancel requested while waiting lock"); +} /* * ProcSleep -- put a process to sleep @@ -566,9 +636,10 @@ ins:; * -------------- */ MemSet(&timeval, 0, sizeof(struct itimerval)); - timeval.it_value.tv_sec = \ - (DeadlockCheckTimer ? DeadlockCheckTimer : DEADLOCK_CHECK_TIMER); + timeval.it_value.tv_sec = DeadlockTimeout / 1000; + timeval.it_value.tv_usec = (DeadlockTimeout % 1000) * 1000; + SetWaitingForLock(true); do { MyProc->errType = NO_ERROR; /* reset flag after deadlock check */ @@ -588,12 +659,14 @@ ins:; IpcExclusiveLock); } while (MyProc->errType == STATUS_NOT_FOUND); /* sleep after deadlock * check */ + lockWaiting = false; /* --------------- * We were awoken before a timeout - now disable the timer * --------------- */ timeval.it_value.tv_sec = 0; + timeval.it_value.tv_usec = 0; if (setitimer(ITIMER_REAL, &timeval, &dummy)) elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup"); @@ -606,7 +679,7 @@ ins:; rt:; -#ifdef LOCK_MGR_DEBUG +#ifdef LOCK_DEBUG /* Just to get meaningful debug messages from DumpLocks() */ MyProc->waitLock = (LOCK *) NULL; #endif @@ -654,7 +727,6 @@ ProcLockWakeup(PROC_QUEUE *queue, LOCKMETHOD lockmethod, LOCK *lock) { PROC *proc; int count = 0; - int trace_flag; int last_locktype = 0; int queue_size = queue->size; @@ -714,14 +786,13 @@ ProcLockWakeup(PROC_QUEUE *queue, LOCKMETHOD lockmethod, LOCK *lock) else { /* Something is still blocking us. May have deadlocked. */ - trace_flag = (lock->tag.lockmethod == USER_LOCKMETHOD) ? \ - TRACE_USERLOCKS : TRACE_LOCKS; - TPRINTF(trace_flag, - "ProcLockWakeup: lock(%x) can't wake up any process", - MAKE_OFFSET(lock)); -#ifdef DEADLOCK_DEBUG - if (pg_options[trace_flag] >= 2) +#ifdef LOCK_DEBUG + if (lock->tag.lockmethod == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks) + { + elog(DEBUG, "ProcLockWakeup: lock(%lx) can't wake up any process", MAKE_OFFSET(lock)); + if (Debug_deadlocks) DumpAllLocks(); + } #endif return STATUS_NOT_FOUND; } @@ -734,7 +805,7 @@ ProcAddLock(SHM_QUEUE *elem) } /* -------------------- - * We only get to this routine if we got SIGALRM after DEADLOCK_CHECK_TIMER + * We only get to this routine if we got SIGALRM after DeadlockTimeout * while waiting for a lock to be released by some other process. If we have * a real deadlock, 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 @@ -783,8 +854,9 @@ HandleDeadLock(SIGNAL_ARGS) return; } -#ifdef DEADLOCK_DEBUG - DumpAllLocks(); +#ifdef LOCK_DEBUG + if (Debug_deadlocks) + DumpAllLocks(); #endif MyProc->errType = STATUS_NOT_FOUND; @@ -801,6 +873,7 @@ HandleDeadLock(SIGNAL_ARGS) * ------------------------ */ Assert(mywaitlock->waitProcs.size > 0); + lockWaiting = false; --mywaitlock->waitProcs.size; SHMQueueDelete(&(MyProc->links)); SHMQueueElemInit(&(MyProc->links));