*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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 <sys/time.h>
#include <unistd.h>
#include <signal.h>
#include <sys/sem.h>
#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 <sys/sem.h>
-#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:
/* 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.
* 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,
/* 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. */
* cleanup dead processes).
*/
- MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
+ MyProc = (PROC *) ShmemAlloc(sizeof(PROC));
if (!MyProc)
{
SpinRelease(ProcStructLock);
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;
}
/*
if (!MyProc)
return;
LockReleaseAll(1, &MyProc->lockQueue);
+ GetOffWaitqueue(MyProc);
}
/*
* 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;
}
{
bool found;
PROC_QUEUE *queue = (PROC_QUEUE *)
- ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
+ ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
if (!queue)
return NULL;
}
+/*
+ * 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
* --------------
*/
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 */
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");
rt:;
-#ifdef LOCK_MGR_DEBUG
+#ifdef LOCK_DEBUG
/* Just to get meaningful debug messages from DumpLocks() */
MyProc->waitLock = (LOCK *) NULL;
#endif
{
PROC *proc;
int count = 0;
- int trace_flag;
int last_locktype = 0;
int queue_size = queue->size;
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;
}
}
/* --------------------
- * 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
return;
}
-#ifdef DEADLOCK_DEBUG
- DumpAllLocks();
+#ifdef LOCK_DEBUG
+ if (Debug_deadlocks)
+ DumpAllLocks();
#endif
MyProc->errType = STATUS_NOT_FOUND;
* ------------------------
*/
Assert(mywaitlock->waitProcs.size > 0);
+ lockWaiting = false;
--mywaitlock->waitProcs.size;
SHMQueueDelete(&(MyProc->links));
SHMQueueElemInit(&(MyProc->links));