diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 1aae86c00257918a258eed8ceec5d14d999d63d1..852a457e2a5557a97f51950f675e4e292319b3e0 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.73 2001/01/12 21:53:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.74 2001/01/14 05:08:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 
 #include "access/heapam.h"
 #include "access/nbtree.h"
+#include "miscadmin.h"
 
 
 typedef struct
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index e3f4a5618f7a3b6decd36fe361af4e84b01fdd6d..e79ada35426e36617e696f1df6a78ba03c70055c 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.92 2001/01/12 21:53:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.93 2001/01/14 05:08:14 tgl Exp $
  *
  * NOTES
  *		Transaction aborts can now occur two ways:
@@ -1015,6 +1015,9 @@ CommitTransaction(void)
 	if (s->state != TRANS_INPROGRESS)
 		elog(NOTICE, "CommitTransaction and not in in-progress state ");
 
+	/* Prevent cancel/die interrupt while cleaning up */
+	START_CRIT_SECTION();
+
 	/* ----------------
 	 *	Tell the trigger manager that this transaction is about to be
 	 *	committed. He'll invoke all trigger deferred until XACT before
@@ -1083,6 +1086,8 @@ CommitTransaction(void)
 	 * ----------------
 	 */
 	s->state = TRANS_DEFAULT;
+
+	END_CRIT_SECTION();
 }
 
 /* --------------------------------
@@ -1095,6 +1100,9 @@ AbortTransaction(void)
 {
 	TransactionState s = CurrentTransactionState;
 
+	/* Prevent cancel/die interrupt while cleaning up */
+	START_CRIT_SECTION();
+
 	/*
 	 * Let others to know about no transaction in progress - vadim
 	 * 11/26/96
@@ -1113,13 +1121,21 @@ AbortTransaction(void)
 	 */
 	ProcReleaseSpins(NULL);
 	UnlockBuffers();
+	/*
+	 * Also clean up any open wait for lock, since the lock manager
+	 * will choke if we try to wait for another lock before doing this.
+	 */
+	LockWaitCancel();
 
 	/* ----------------
 	 *	check the current transaction state
 	 * ----------------
 	 */
 	if (s->state == TRANS_DISABLED)
+	{
+		END_CRIT_SECTION();
 		return;
+	}
 
 	if (s->state != TRANS_INPROGRESS)
 		elog(NOTICE, "AbortTransaction and not in in-progress state");
@@ -1169,6 +1185,7 @@ AbortTransaction(void)
 	 *	State remains TRANS_ABORT until CleanupTransaction().
 	 * ----------------
 	 */
+	END_CRIT_SECTION();
 }
 
 /* --------------------------------
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index e995b06f914f76a5473b43d3bc4510ea15dce820..5777e035d4626773944ed3c0cad4b42d44535c02 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.49 2001/01/12 21:53:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.50 2001/01/14 05:08:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,7 +42,6 @@
 int			XLOGbuffers = 8;
 int			XLOGfiles = 0;	/* how many files to pre-allocate */
 XLogRecPtr	MyLastRecPtr = {0, 0};
-volatile uint32 CritSectionCount = 0;
 bool		InRecovery = false;
 StartUpID	ThisStartUpID = 0;
 XLogRecPtr	RedoRecPtr;
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index cd4186eec83668304a2342d79ac07580fca830ab..19b421a51d4f6d251fb6f5b2578ebab876fd10f5 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.102 2000/12/28 13:00:12 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.103 2001/01/14 05:08:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -329,9 +329,10 @@ BootstrapMain(int argc, char *argv[])
 
 	if (!IsUnderPostmaster)
 	{
-		pqsignal(SIGINT, (pqsigfunc) die);
-		pqsignal(SIGHUP, (pqsigfunc) die);
-		pqsignal(SIGTERM, (pqsigfunc) die);
+		pqsignal(SIGHUP, die);
+		pqsignal(SIGINT, die);
+		pqsignal(SIGTERM, die);
+		pqsignal(SIGQUIT, die);
 	}
 
 	/*
@@ -383,8 +384,6 @@ BootstrapMain(int argc, char *argv[])
 	 *	abort processing resumes here
 	 * ----------------
 	 */
-	pqsignal(SIGHUP, handle_warn);
-
 	if (sigsetjmp(Warn_restart, 1) != 0)
 	{
 		Warnings++;
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index a1dee895b3fd16336f51522d89217220dd9da21d..889cd5316e81156142cc1ff99c34219aec6f26ca 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.10 2000/12/02 19:38:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.11 2001/01/14 05:08:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,8 +72,7 @@ analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
 	 * Check for user-requested abort.	Note we want this to be inside a
 	 * transaction, so xact.c doesn't issue useless NOTICE.
 	 */
-	if (QueryCancel)
-		CancelQuery();
+	CHECK_FOR_INTERRUPTS();
 
 	/*
 	 * Race condition -- if the pg_class tuple has gone away since the
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index f33c6e9eb4c85a3383ff93dbf9a0932c76fe79b9..25f6bace81e6925a5b430eb86eab3597c7c8aed4 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.128 2001/01/06 03:33:17 ishii Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.129 2001/01/14 05:08:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -449,8 +449,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
 	{
 		bool		need_delim = false;
 
-		if (QueryCancel)
-			CancelQuery();
+		CHECK_FOR_INTERRUPTS();
 
 		if (binary)
 		{
@@ -702,11 +701,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
 
 	while (!done)
 	{
-		if (QueryCancel)
-		{
-			lineno = 0;
-			CancelQuery();
-		}
+		CHECK_FOR_INTERRUPTS();
 
 		lineno++;
 
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 76425652b9703b134062cbc38b6508e8a05e1052..2a402004ca0870a970605c51aa537033049374f6 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.182 2001/01/12 21:53:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.183 2001/01/14 05:08:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -378,8 +378,7 @@ vacuum_rel(Oid relid)
 	 * Check for user-requested abort.	Note we want this to be inside a
 	 * transaction, so xact.c doesn't issue useless NOTICE.
 	 */
-	if (QueryCancel)
-		CancelQuery();
+	CHECK_FOR_INTERRUPTS();
 
 	/*
 	 * Race condition -- if the pg_class tuple has gone away since the
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index d7db099653dccaf66af1f4ee5fcc8696e6b8d7aa..6cc2a1aed97e605b29851071c09ebbda9c09c38f 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.22 2000/10/26 21:35:15 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.23 2001/01/14 05:08:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -248,14 +248,12 @@ ExecProcNode(Plan *node, Plan *parent)
 {
 	TupleTableSlot *result;
 
+	CHECK_FOR_INTERRUPTS();
+
 	/* ----------------
 	 *	deal with NULL nodes..
 	 * ----------------
 	 */
-
-	if (QueryCancel)
-		CancelQuery();
-
 	if (node == NULL)
 		return NULL;
 
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 2be519193bbf6fb253fff99d4f3a65ac9f1966be..6b897588621ade9c8e4e07ac4bf137c9e506ec3b 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.103 2001/01/12 21:53:57 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.104 2001/01/14 05:08:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,6 +92,7 @@ static Buffer ReadBufferWithBufferLock(Relation relation, BlockNumber blockNum,
 						 bool bufferLockHeld);
 static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
 			bool *foundPtr, bool bufferLockHeld);
+static int	ReleaseBufferWithBufferLock(Buffer buffer);
 static int	BufferReplace(BufferDesc *bufHdr);
 void		PrintBufferDescs(void);
 
@@ -687,10 +688,14 @@ ReleaseAndReadBuffer(Buffer buffer,
 		{
 			bufHdr = &BufferDescriptors[buffer - 1];
 			Assert(PrivateRefCount[buffer - 1] > 0);
-			PrivateRefCount[buffer - 1]--;
-			if (PrivateRefCount[buffer - 1] == 0)
+			if (PrivateRefCount[buffer - 1] > 1)
+			{
+				PrivateRefCount[buffer - 1]--;
+			}
+			else
 			{
 				SpinAcquire(BufMgrLock);
+				PrivateRefCount[buffer - 1] = 0;
 				Assert(bufHdr->refcount > 0);
 				bufHdr->refcount--;
 				if (bufHdr->refcount == 0)
@@ -1185,10 +1190,7 @@ recheck:
 				/* Assert checks that buffer will actually get freed! */
 				Assert(PrivateRefCount[i - 1] == 1 &&
 					   bufHdr->refcount == 1);
-				/* ReleaseBuffer expects we do not hold the lock at entry */
-				SpinRelease(BufMgrLock);
-				ReleaseBuffer(i);
-				SpinAcquire(BufMgrLock);
+				ReleaseBufferWithBufferLock(i);
 			}
 			/*
 			 * And mark the buffer as no longer occupied by this rel.
@@ -1270,10 +1272,7 @@ recheck:
 				/* Assert checks that buffer will actually get freed! */
 				Assert(PrivateRefCount[i - 1] == 1 &&
 					   bufHdr->refcount == 1);
-				/* ReleaseBuffer expects we do not hold the lock at entry */
-				SpinRelease(BufMgrLock);
-				ReleaseBuffer(i);
-				SpinAcquire(BufMgrLock);
+				ReleaseBufferWithBufferLock(i);
 			}
 			/*
 			 * And mark the buffer as no longer occupied by this rel.
@@ -1624,10 +1623,14 @@ ReleaseBuffer(Buffer buffer)
 	bufHdr = &BufferDescriptors[buffer - 1];
 
 	Assert(PrivateRefCount[buffer - 1] > 0);
-	PrivateRefCount[buffer - 1]--;
-	if (PrivateRefCount[buffer - 1] == 0)
+	if (PrivateRefCount[buffer - 1] > 1)
+	{
+		PrivateRefCount[buffer - 1]--;
+	}
+	else
 	{
 		SpinAcquire(BufMgrLock);
+		PrivateRefCount[buffer - 1] = 0;
 		Assert(bufHdr->refcount > 0);
 		bufHdr->refcount--;
 		if (bufHdr->refcount == 0)
@@ -1641,6 +1644,48 @@ ReleaseBuffer(Buffer buffer)
 	return STATUS_OK;
 }
 
+/*
+ * ReleaseBufferWithBufferLock
+ *		Same as ReleaseBuffer except we hold the lock
+ */
+static int
+ReleaseBufferWithBufferLock(Buffer buffer)
+{
+	BufferDesc *bufHdr;
+
+	if (BufferIsLocal(buffer))
+	{
+		Assert(LocalRefCount[-buffer - 1] > 0);
+		LocalRefCount[-buffer - 1]--;
+		return STATUS_OK;
+	}
+
+	if (BAD_BUFFER_ID(buffer))
+		return STATUS_ERROR;
+
+	bufHdr = &BufferDescriptors[buffer - 1];
+
+	Assert(PrivateRefCount[buffer - 1] > 0);
+	if (PrivateRefCount[buffer - 1] > 1)
+	{
+		PrivateRefCount[buffer - 1]--;
+	}
+	else
+	{
+		PrivateRefCount[buffer - 1] = 0;
+		Assert(bufHdr->refcount > 0);
+		bufHdr->refcount--;
+		if (bufHdr->refcount == 0)
+		{
+			AddBufferToFreelist(bufHdr);
+			bufHdr->flags |= BM_FREE;
+		}
+	}
+
+	return STATUS_OK;
+}
+
+
 #ifdef NOT_USED
 void
 IncrBufferRefCount_Debug(char *file, int line, Buffer buffer)
@@ -2217,9 +2262,9 @@ MarkBufferForCleanup(Buffer buffer, void (*CleanupFunc)(Buffer))
 		SpinRelease(BufMgrLock);
 
 	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
-	PrivateRefCount[buffer - 1]--;
 
 	SpinAcquire(BufMgrLock);
+	PrivateRefCount[buffer - 1] = 0;
 	Assert(bufHdr->refcount > 0);
 	bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
 	bufHdr->CleanupFunc = CleanupFunc;
diff --git a/src/backend/storage/buffer/s_lock.c b/src/backend/storage/buffer/s_lock.c
index 932e5b0049b9dcfc41a155d170c4065c15d9e9da..00a934c38321f1c4eb9d953af37489c65a9dd084 100644
--- a/src/backend/storage/buffer/s_lock.c
+++ b/src/backend/storage/buffer/s_lock.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.28 2000/12/29 21:31:20 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.29 2001/01/14 05:08:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 #include <sys/time.h>
 #include <unistd.h>
 
+#include "miscadmin.h"
 #include "storage/s_lock.h"
 
 
@@ -101,10 +102,16 @@ s_lock(volatile slock_t *lock, const char *file, const int line)
 	/*
 	 * If you are thinking of changing this code, be careful.  This same
 	 * loop logic is used in other places that call TAS() directly.
+	 *
+	 * While waiting for a lock, we check for cancel/die interrupts (which
+	 * is a no-op if we are inside a critical section).  The interrupt check
+	 * can be omitted in places that know they are inside a critical section.
+	 * Note that an interrupt must NOT be accepted after acquiring the lock.
 	 */
 	while (TAS(lock))
 	{
 		s_lock_sleep(spins++, 0, lock, file, line);
+		CHECK_FOR_INTERRUPTS();
 	}
 }
 
diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c
index d592a17986702c763876800fb89d2548a5115888..9d796299dc6af293040a63a1735b49f6a1c6d0a1 100644
--- a/src/backend/storage/ipc/ipc.c
+++ b/src/backend/storage/ipc/ipc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.59 2001/01/07 04:30:41 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.60 2001/01/14 05:08:15 tgl Exp $
  *
  * NOTES
  *
@@ -131,8 +131,12 @@ proc_exit(int code)
 	 * to close up shop already.  Note that the signal handlers will not
 	 * set these flags again, now that proc_exit_inprogress is set.
 	 */
-	QueryCancel = false;
+	InterruptPending = false;
 	ProcDiePending = false;
+	QueryCancelPending = false;
+	/* And let's just make *sure* we're not interrupted ... */
+	ImmediateInterruptOK = false;
+	CritSectionCount = 1;
 
 	if (DebugLvl > 1)
 		elog(DEBUG, "proc_exit(%d)", code);
@@ -367,7 +371,7 @@ CallbackSemaphoreKill(int status, Datum semId)
 /*	 IpcSemaphoreLock(semId, sem) - locks a semaphore						*/
 /****************************************************************************/
 void
-IpcSemaphoreLock(IpcSemaphoreId semId, int sem)
+IpcSemaphoreLock(IpcSemaphoreId semId, int sem, bool interruptOK)
 {
 	int			errStatus;
 	struct sembuf sops;
@@ -380,11 +384,43 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem)
 	 *	Note: if errStatus is -1 and errno == EINTR then it means we
 	 *		  returned from the operation prematurely because we were
 	 *		  sent a signal.  So we try and lock the semaphore again.
-	 * ----------------
+	 *
+	 *	Each time around the loop, we check for a cancel/die interrupt.
+	 *	We assume that if such an interrupt comes in while we are waiting,
+	 *	it will cause the semop() call to exit with errno == EINTR, so that
+	 *	we will be able to service the interrupt (if not in a critical
+	 *	section already).
+	 *
+	 *	Once we acquire the lock, we do NOT check for an interrupt before
+	 *	returning.  The caller needs to be able to record ownership of
+	 *	the lock before any interrupt can be accepted.
+	 *
+	 *	There is a window of a few instructions between CHECK_FOR_INTERRUPTS
+	 *	and entering the semop() call.  If a cancel/die interrupt occurs in
+	 *	that window, we would fail to notice it until after we acquire the
+	 *	lock (or get another interrupt to escape the semop()).  We can avoid
+	 *	this problem by temporarily setting ImmediateInterruptOK = true
+	 *	before we do CHECK_FOR_INTERRUPTS; then, a die() interrupt in this
+	 *	interval will execute directly.  However, there is a huge pitfall:
+	 *	there is another window of a few instructions after the semop()
+	 *	before we are able to reset ImmediateInterruptOK.  If an interrupt
+	 *	occurs then, we'll lose control, which means that the lock has been
+	 *	acquired but our caller did not get a chance to record the fact.
+	 *	Therefore, we only set ImmediateInterruptOK if the caller tells us
+	 *	it's OK to do so, ie, the caller does not need to record acquiring
+	 *	the lock.  (This is currently true for lockmanager locks, since the
+	 *	process that granted us the lock did all the necessary state updates.
+	 *	It's not true for SysV semaphores used to emulate spinlocks --- but
+	 *	our performance on such platforms is so horrible anyway that I'm
+	 *	not going to worry too much about it.)
+	 *	----------------
 	 */
 	do
 	{
+		ImmediateInterruptOK = interruptOK;
+		CHECK_FOR_INTERRUPTS();
 		errStatus = semop(semId, &sops, 1);
+		ImmediateInterruptOK = false;
 	} while (errStatus == -1 && errno == EINTR);
 
 	if (errStatus == -1)
diff --git a/src/backend/storage/ipc/spin.c b/src/backend/storage/ipc/spin.c
index ed71d79ad9f3cb7b278e502a4a44377f3bc37d3d..b27c181002025b27122bdb8ae1defc4e019bb0c3 100644
--- a/src/backend/storage/ipc/spin.c
+++ b/src/backend/storage/ipc/spin.c
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.28 2001/01/12 21:53:59 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.29 2001/01/14 05:08:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,9 +25,11 @@
 #include <sys/sem.h>
 #endif
 
+#include "miscadmin.h"
 #include "storage/proc.h"
 #include "storage/s_lock.h"
 
+
 /* Probably should move these to an appropriate header file */
 extern SPINLOCK ShmemLock;
 extern SPINLOCK ShmemIndexLock;
@@ -144,20 +146,21 @@ SpinAcquire(SPINLOCK lockid)
 	SLock	   *slckP = &(SLockArray[lockid]);
 
 	PRINT_SLDEBUG("SpinAcquire", lockid, slckP);
-	/*
-	 * Lock out die() until we exit the critical section protected by the
-	 * spinlock.  This ensures that die() will not interrupt manipulations
-	 * of data structures in shared memory.  We don't want die() to
-	 * interrupt this routine between S_LOCK and PROC_INCR_SLOCK, either,
-	 * so must do it before acquiring the lock, not after.
-	 */
-	START_CRIT_SECTION();
 	/*
 	 * Acquire the lock, then record that we have done so (for recovery
-	 * in case of elog(ERROR) during the critical section).
+	 * in case of elog(ERROR) during the critical section).  Note we assume
+	 * here that S_LOCK will not accept cancel/die interrupts once it has
+	 * acquired the lock.  However, interrupts should be accepted while
+	 * waiting, if CritSectionCount is zero.
 	 */
 	S_LOCK(&(slckP->shlock));
 	PROC_INCR_SLOCK(lockid);
+	/*
+	 * Lock out cancel/die interrupts until we exit the critical section
+	 * protected by the spinlock.  This ensures that interrupts will not
+	 * interfere with manipulations of data structures in shared memory.
+	 */
+	START_CRIT_SECTION();
 
     PRINT_SLDEBUG("SpinAcquire/done", lockid, slckP);
 }
@@ -317,10 +320,16 @@ SpinFreeAllSemaphores(void)
 void
 SpinAcquire(SPINLOCK lock)
 {
-	/* See the TAS() version of this routine for commentary */
-	START_CRIT_SECTION();
-	IpcSemaphoreLock(SpinLockIds[0], lock);
+	/*
+	 * See the TAS() version of this routine for primary commentary.
+	 *
+	 * NOTE we must pass interruptOK = false to IpcSemaphoreLock, to ensure
+	 * that a cancel/die interrupt cannot prevent us from recording ownership
+	 * of a lock we have just acquired.
+	 */
+	IpcSemaphoreLock(SpinLockIds[0], lock, false);
 	PROC_INCR_SLOCK(lock);
+	START_CRIT_SECTION();
 }
 
 /*
@@ -338,8 +347,8 @@ SpinRelease(SPINLOCK lock)
 
 	semval = IpcSemaphoreGetValue(SpinLockIds[0], lock);
 	Assert(semval < 1);
-    Assert(!MyProc || MyProc->sLocks[lockid] > 0);
 #endif
+    Assert(!MyProc || MyProc->sLocks[lockid] > 0);
 	PROC_DECR_SLOCK(lock);
 	IpcSemaphoreUnlock(SpinLockIds[0], lock);
 	END_CRIT_SECTION();
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index f15ee9f8bd6f0492faf25313da168ce08cfc63b4..e7d1b678bef61e4655a89505259fb46d0c1ac1ed 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.76 2001/01/10 01:24:19 inoue Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.77 2001/01/14 05:08:15 tgl Exp $
  *
  * NOTES
  *	  Outside modules can create a lock table and acquire/release
@@ -726,6 +726,12 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
 		 */
 		status = WaitOnLock(lockmethod, lockmode, lock, holder);
 
+		/*
+		 * NOTE: do not do any material change of state between here and
+		 * return.  All required changes in locktable state must have been
+		 * done when the lock was granted to us --- see notes in WaitOnLock.
+		 */
+
 		/*
 		 * Check the holder entry status, in case something in the ipc
 		 * communication doesn't work correctly.
@@ -921,6 +927,8 @@ GrantLock(LOCK *lock, HOLDER *holder, LOCKMODE lockmode)
 	lock->nActive++;
 	lock->activeHolders[lockmode]++;
 	lock->mask |= BITS_ON[lockmode];
+	if (lock->activeHolders[lockmode] == lock->holders[lockmode])
+		lock->waitMask &= BITS_OFF[lockmode];
 	LOCK_PRINT("GrantLock", lock, lockmode);
 	Assert((lock->nActive > 0) && (lock->activeHolders[lockmode] > 0));
 	Assert(lock->nActive <= lock->nHolding);
@@ -960,6 +968,17 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
 	strcat(new_status, " waiting");
 	set_ps_display(new_status);
 
+	/*
+	 * NOTE: Think not to put any lock state cleanup after the call to
+	 * ProcSleep, in either the normal or failure path.  The lock state
+	 * must be fully set by the lock grantor, or by HandleDeadlock if we
+	 * give up waiting for the lock.  This is necessary because of the
+	 * possibility that a cancel/die interrupt will interrupt ProcSleep
+	 * after someone else grants us the lock, but before we've noticed it.
+	 * Hence, after granting, the locktable state must fully reflect the
+	 * fact that we own the lock; we can't do additional work on return.
+	 */
+
 	if (ProcSleep(lockMethodTable->ctl,
 				  lockmode,
 				  lock,
@@ -967,26 +986,16 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
 	{
 		/* -------------------
 		 * We failed as a result of a deadlock, see HandleDeadLock().
-		 * Decrement the lock nHolding and holders fields as
-		 * we are no longer waiting on this lock.  Removal of the holder and
-		 * lock objects, if no longer needed, will happen in xact cleanup.
+		 * Quit now.  Removal of the holder and lock objects, if no longer
+		 * needed, will happen in xact cleanup (see above for motivation).
 		 * -------------------
 		 */
-		lock->nHolding--;
-		lock->holders[lockmode]--;
 		LOCK_PRINT("WaitOnLock: aborting on lock", lock, lockmode);
-		Assert((lock->nHolding >= 0) && (lock->holders[lockmode] >= 0));
-		Assert(lock->nActive <= lock->nHolding);
-		if (lock->activeHolders[lockmode] == lock->holders[lockmode])
-			lock->waitMask &= BITS_OFF[lockmode];
 		SpinRelease(lockMethodTable->ctl->masterLock);
 		elog(ERROR, DeadLockMessage);
 		/* not reached */
 	}
 
-	if (lock->activeHolders[lockmode] == lock->holders[lockmode])
-		lock->waitMask &= BITS_OFF[lockmode];
-
 	set_ps_display(old_status);
 	pfree(old_status);
 	pfree(new_status);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index baa31413e2fefd5c8ebda9a81f39b8c0246c74b8..b5a22bb2321b5032b3f54bd06e52150fe56f8141 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.91 2001/01/12 21:53:59 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.92 2001/01/14 05:08:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,7 +48,7 @@
  *		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.91 2001/01/12 21:53:59 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.92 2001/01/14 05:08:16 tgl Exp $
  */
 #include "postgres.h"
 
@@ -78,11 +78,6 @@
 #include "storage/proc.h"
 
 
-
-void		HandleDeadLock(SIGNAL_ARGS);
-static void ProcFreeAllSemaphores(void);
-static bool GetOffWaitQueue(PROC *);
-
 int DeadlockTimeout = 1000;
 
 /* --------------------
@@ -98,9 +93,14 @@ static PROC_HDR *ProcGlobal = NULL;
 
 PROC	   *MyProc = NULL;
 
-static void ProcKill(int exitStatus, Datum pid);
+static bool waitingForLock = false;
+
+static void ProcKill(void);
 static void ProcGetNewSemIdAndNum(IpcSemaphoreId *semId, int *semNum);
 static void ProcFreeSem(IpcSemaphoreId semId, int semNum);
+static void ZeroProcSemaphore(PROC *proc);
+static void ProcFreeAllSemaphores(void);
+
 
 /*
  * InitProcGlobal -
@@ -241,27 +241,23 @@ InitProcess(void)
 	MemSet(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
 	MyProc->sLocks[ProcStructLock] = 1;
 
+	/*
+	 * Set up a wait-semaphore for the proc.
+	 */
 	if (IsUnderPostmaster)
 	{
-		IpcSemaphoreId	semId;
-		int				semNum;
-		union semun		semun;
-
-		ProcGetNewSemIdAndNum(&semId, &semNum);
-
+		ProcGetNewSemIdAndNum(&MyProc->sem.semId, &MyProc->sem.semNum);
 		/*
 		 * we might be reusing a semaphore that belongs to a dead backend.
 		 * So be careful and reinitialize its value here.
 		 */
-		semun.val = 1;
-		semctl(semId, semNum, SETVAL, semun);
-
-		IpcSemaphoreLock(semId, semNum);
-		MyProc->sem.semId = semId;
-		MyProc->sem.semNum = semNum;
+		ZeroProcSemaphore(MyProc);
 	}
 	else
+	{
 		MyProc->sem.semId = -1;
+		MyProc->sem.semNum = -1;
+	}
 
 	MyProc->pid = MyProcPid;
 	MyProc->databaseId = MyDatabaseId;
@@ -282,67 +278,126 @@ InitProcess(void)
 	 * -------------------------
 	 */
 	location = MAKE_OFFSET(MyProc);
-	if ((!ShmemPIDLookup(MyProcPid, &location)) || (location != MAKE_OFFSET(MyProc)))
+	if ((!ShmemPIDLookup(MyProcPid, &location)) ||
+		(location != MAKE_OFFSET(MyProc)))
 		elog(STOP, "InitProcess: ShmemPID table broken");
 
 	MyProc->errType = NO_ERROR;
 	SHMQueueElemInit(&(MyProc->links));
 
-	on_shmem_exit(ProcKill, (Datum) MyProcPid);
+	on_shmem_exit(ProcKill, 0);
 }
 
-/* -----------------------
- * get process off any wait queue it might be on
+/*
+ * Initialize the proc's wait-semaphore to count zero.
+ */
+static void
+ZeroProcSemaphore(PROC *proc)
+{
+	union semun		semun;
+
+	semun.val = 0;
+	if (semctl(proc->sem.semId, proc->sem.semNum, SETVAL, semun) < 0)
+	{
+		fprintf(stderr, "ZeroProcSemaphore: semctl(id=%d,SETVAL) failed: %s\n",
+				proc->sem.semId, strerror(errno));
+		proc_exit(255);
+	}
+}
+
+/*
+ * Remove a proc from the wait-queue it is on
+ * (caller must know it is on one).
+ * Locktable lock must be held by caller.
  *
  * NB: this does not remove the process' holder object, nor the lock object,
  * even though their holder counts might now have gone to zero.  That will
  * happen during a subsequent LockReleaseAll call, which we expect will happen
  * during transaction cleanup.  (Removal of a proc from its wait queue by
  * this routine can only happen if we are aborting the transaction.)
- * -----------------------
  */
-static bool
-GetOffWaitQueue(PROC *proc)
+static void
+RemoveFromWaitQueue(PROC *proc)
 {
-	bool		gotoff = false;
+	LOCK   *waitLock = proc->waitLock;
+	LOCKMODE lockmode = proc->waitLockMode;
 
-	LockLockTable();
-	if (proc->links.next != INVALID_OFFSET)
+	/* Make sure proc is waiting */
+	Assert(proc->links.next != INVALID_OFFSET);
+	Assert(waitLock);
+	Assert(waitLock->waitProcs.size > 0);
+
+	/* Remove proc from lock's wait queue */
+	SHMQueueDelete(&(proc->links));
+	waitLock->waitProcs.size--;
+
+	/* Undo increments of holder counts by waiting process */
+	Assert(waitLock->nHolding > 0);
+	Assert(waitLock->nHolding > proc->waitLock->nActive);
+	waitLock->nHolding--;
+	Assert(waitLock->holders[lockmode] > 0);
+	waitLock->holders[lockmode]--;
+	/* don't forget to clear waitMask bit if appropriate */
+	if (waitLock->activeHolders[lockmode] == waitLock->holders[lockmode])
+		waitLock->waitMask &= ~(1 << lockmode);
+
+	/* Clean up the proc's own state */
+	SHMQueueElemInit(&(proc->links));
+	proc->waitLock = NULL;
+	proc->waitHolder = NULL;
+
+	/* See if any other waiters for the lock can be woken up now */
+	ProcLockWakeup(LOCK_LOCKMETHOD(*waitLock), waitLock);
+}
+
+/*
+ * Cancel any pending wait for lock, when aborting a transaction.
+ *
+ * (Normally, this would only happen if we accept a cancel/die
+ * interrupt while waiting; but an elog(ERROR) while waiting is
+ * within the realm of possibility, too.)
+ */
+void
+LockWaitCancel(void)
+{
+	/* Nothing to do if we weren't waiting for a lock */
+	if (!waitingForLock)
+		return;
+	waitingForLock = false;
+
+	/* Turn off the deadlock timer, if it's still running (see ProcSleep) */
+#ifndef __BEOS__
 	{
-		LOCK   *waitLock = proc->waitLock;
-		LOCKMODE lockmode = proc->waitLockMode;
-
-		/* Remove proc from lock's wait queue */
-		Assert(waitLock);
-		Assert(waitLock->waitProcs.size > 0);
-		SHMQueueDelete(&(proc->links));
-		--waitLock->waitProcs.size;
-
-		/* Undo increments of holder counts by waiting process */
-		Assert(waitLock->nHolding > 0);
-		Assert(waitLock->nHolding > proc->waitLock->nActive);
-		--waitLock->nHolding;
-		Assert(waitLock->holders[lockmode] > 0);
-		--waitLock->holders[lockmode];
-		/* don't forget to clear waitMask bit if appropriate */
-		if (waitLock->activeHolders[lockmode] == waitLock->holders[lockmode])
-			waitLock->waitMask &= ~(1 << lockmode);
-
-		/* Clean up the proc's own state */
-		SHMQueueElemInit(&(proc->links));
-		proc->waitLock = NULL;
-		proc->waitHolder = NULL;
-
-		/* See if any other waiters can be woken up now */
-		ProcLockWakeup(LOCK_LOCKMETHOD(*waitLock), waitLock);
-
-		gotoff = true;
+		struct itimerval timeval,
+						 dummy;
+
+		MemSet(&timeval, 0, sizeof(struct itimerval));
+		setitimer(ITIMER_REAL, &timeval, &dummy);
 	}
+#else
+	/* BeOS doesn't have setitimer, but has set_alarm */
+    set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM);
+#endif /* __BEOS__ */
+
+	/* Unlink myself from the wait queue, if on it (might not be anymore!) */
+	LockLockTable();
+	if (MyProc->links.next != INVALID_OFFSET)
+		RemoveFromWaitQueue(MyProc);
 	UnlockLockTable();
 
-	return gotoff;
+	/*
+	 * Reset the proc wait semaphore to zero.  This is necessary in the
+	 * scenario where someone else granted us the lock we wanted before we
+	 * were able to remove ourselves from the wait-list.  The semaphore will
+	 * have been bumped to 1 by the would-be grantor, and since we are no
+	 * longer going to wait on the sema, we have to force it back to zero.
+	 * Otherwise, our next attempt to wait for a lock will fall through
+	 * prematurely.
+	 */
+	ZeroProcSemaphore(MyProc);
 }
 
+
 /*
  * ProcReleaseLocks() -- release locks associated with current transaction
  *			at transaction commit or abort
@@ -360,15 +415,17 @@ ProcReleaseLocks(bool isCommit)
 {
 	if (!MyProc)
 		return;
-	GetOffWaitQueue(MyProc);
+	/* If waiting, get off wait queue (should only be needed after error) */
+	LockWaitCancel();
+	/* Release locks */
 	LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc,
 				   !isCommit, GetCurrentTransactionId());
 }
 
 /*
  * ProcRemove -
- *	  used by the postmaster to clean up the global tables. This also frees
- *	  up the semaphore used for the lmgr of the process.
+ *	  called by the postmaster to clean up the global tables after a
+ *	  backend exits.  This also frees up the proc's wait semaphore.
  */
 bool
 ProcRemove(int pid)
@@ -376,8 +433,6 @@ ProcRemove(int pid)
 	SHMEM_OFFSET location;
 	PROC	   *proc;
 
-	location = INVALID_OFFSET;
-
 	location = ShmemPIDDestroy(pid);
 	if (location == INVALID_OFFSET)
 		return FALSE;
@@ -398,43 +453,30 @@ ProcRemove(int pid)
 /*
  * ProcKill() -- Destroy the per-proc data structure for
  *		this process. Release any of its held spin locks.
+ *
+ * This is done inside the backend process before it exits.
+ * ProcRemove, above, will be done by the postmaster afterwards.
  */
 static void
-ProcKill(int exitStatus, Datum pid)
+ProcKill(void)
 {
-	PROC	   *proc;
-
-	if ((int) pid == MyProcPid)
-	{
-		proc = MyProc;
-		MyProc = NULL;
-	}
-	else
-	{
-		/* This path is dead code at the moment ... */
-		SHMEM_OFFSET location = INVALID_OFFSET;
-
-		ShmemPIDLookup((int) pid, &location);
-		if (location == INVALID_OFFSET)
-			return;
-		proc = (PROC *) MAKE_PTR(location);
-	}
-
-	Assert(proc);
+	Assert(MyProc);
 
-	/* Release any spinlocks the proc is holding */
-	ProcReleaseSpins(proc);
+	/* Release any spinlocks I am holding */
+	ProcReleaseSpins(MyProc);
 
-	/* Get the proc off any wait queue it might be on */
-	GetOffWaitQueue(proc);
+	/* Get off any wait queue I might be on */
+	LockWaitCancel();
 
 	/* Remove from the standard lock table */
-	LockReleaseAll(DEFAULT_LOCKMETHOD, proc, true, InvalidTransactionId);
+	LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc, true, InvalidTransactionId);
 
 #ifdef USER_LOCKS
 	/* Remove from the user lock table */
-	LockReleaseAll(USER_LOCKMETHOD, proc, true, InvalidTransactionId);
+	LockReleaseAll(USER_LOCKMETHOD, MyProc, true, InvalidTransactionId);
 #endif
+
+	MyProc = NULL;
 }
 
 /*
@@ -476,69 +518,14 @@ 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 for lock");
-			}
-		}
-	}
-}
-
-void
-LockWaitCancel(void)
-{
-#ifndef __BEOS__ 	
-	struct itimerval timeval,
-				dummy;
-
-	if (!lockWaiting)
-		return;
-	lockWaiting = false;
-	/* Deadlock timer off */
-	MemSet(&timeval, 0, sizeof(struct itimerval));
-	setitimer(ITIMER_REAL, &timeval, &dummy);
-#else
-	/* BeOS doesn't have setitimer, but has set_alarm */
-	if (!lockWaiting)
-		return;
-	lockWaiting = false;
-	/* Deadlock timer off */
-    set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM);
-#endif /* __BEOS__ */
-        
-	if (GetOffWaitQueue(MyProc))
-		elog(ERROR, "Query cancel requested while waiting for lock");
-}
-
 /*
  * ProcSleep -- put a process to sleep
  *
  * P() on the semaphore should put us to sleep.  The process
- * semaphore is cleared by default, so the first time we try
- * to acquire it, we sleep.
+ * semaphore is normally zero, so when we try to acquire it, we sleep.
+ *
+ * Locktable's spinlock must be held at entry, and will be held
+ * at exit.
  *
  * Result is NO_ERROR if we acquired the lock, STATUS_ERROR if not (deadlock).
  *
@@ -629,7 +616,7 @@ ProcSleep(LOCKMETHODCTL *lockctl,
 
 ins:;
 	/* -------------------
-	 * assume that these two operations are atomic (because
+	 * Insert self into queue.  These operations are atomic (because
 	 * of the spinlock).
 	 * -------------------
 	 */
@@ -640,6 +627,18 @@ ins:;
 
 	MyProc->errType = NO_ERROR;		/* initialize result for success */
 
+	/* mark that we are waiting for a lock */
+	waitingForLock = true;
+
+	/* -------------------
+	 * Release the locktable's spin lock.
+	 *
+	 * NOTE: this may also cause us to exit critical-section state,
+	 * possibly allowing a cancel/die interrupt to be accepted.
+	 * This is OK because we have recorded the fact that we are waiting for
+	 * a lock, and so LockWaitCancel will clean up if cancel/die happens.
+	 * -------------------
+	 */
 	SpinRelease(spinlock);
 
 	/* --------------
@@ -667,8 +666,6 @@ ins:;
 		elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
 #endif
 
-	SetWaitingForLock(true);
-
 	/* --------------
 	 * If someone wakes us between SpinRelease and IpcSemaphoreLock,
 	 * IpcSemaphoreLock will not block.  The wakeup is "saved" by
@@ -676,19 +673,22 @@ ins:;
 	 * is invoked but does not detect a deadlock, IpcSemaphoreLock()
 	 * will continue to wait.  There used to be a loop here, but it
 	 * was useless code...
+	 *
+	 * We pass interruptOK = true, which eliminates a window in which
+	 * cancel/die interrupts would be held off undesirably.  This is a
+	 * promise that we don't mind losing control to a cancel/die interrupt
+	 * here.  We don't, because we have no state-change work to do after
+	 * being granted the lock (the grantor did it all).
 	 * --------------
 	 */
-	IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum);
-
-	lockWaiting = false;
+	IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, true);
 
 	/* ---------------
 	 * Disable the timer, if it's still running
 	 * ---------------
 	 */
 #ifndef __BEOS__
-	timeval.it_value.tv_sec = 0;
-	timeval.it_value.tv_usec = 0;
+	MemSet(&timeval, 0, sizeof(struct itimerval));
 	if (setitimer(ITIMER_REAL, &timeval, &dummy))
 		elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
 #else
@@ -696,9 +696,16 @@ ins:;
 		elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
 #endif
 
+	/*
+	 * Now there is nothing for LockWaitCancel to do.
+	 */
+	waitingForLock = false;
+
 	/* ----------------
-	 * We were assumed to be in a critical section when we went
-	 * to sleep.
+	 * Re-acquire the locktable's spin lock.
+	 *
+	 * We could accept a cancel/die interrupt here.  That's OK because
+	 * the lock is now registered as being held by this process.
 	 * ----------------
 	 */
 	SpinAcquire(spinlock);
@@ -836,20 +843,24 @@ ProcAddLock(SHM_QUEUE *elem)
 
 /* --------------------
  * 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
- * up my semaphore.
+ * while waiting for a lock to be released by some other process.  Look
+ * to see if there's a deadlock; if not, just return and continue waiting.
+ * If we have a real deadlock, remove ourselves from the lock's wait queue
+ * and signal an error to ProcSleep.
  * --------------------
  */
 void
 HandleDeadLock(SIGNAL_ARGS)
 {
 	int			save_errno = errno;
-	LOCK	   *mywaitlock;
-	bool	isWaitingForLock = lockWaiting; /* save waiting status */
 
-	SetWaitingForLock(false); /* disable query cancel during this fuction */
+	/*
+	 * Acquire locktable lock.  Note that the SIGALRM interrupt had better
+	 * not be enabled anywhere that this process itself holds the locktable
+	 * lock, else this will wait forever.  Also note that this calls
+	 * SpinAcquire which creates a critical section, so that this routine
+	 * cannot be interrupted by cancel/die interrupts.
+	 */
 	LockLockTable();
 
 	/* ---------------------
@@ -869,7 +880,6 @@ HandleDeadLock(SIGNAL_ARGS)
 	{
 		UnlockLockTable();
 		errno = save_errno;
-		SetWaitingForLock(isWaitingForLock); /* restore waiting status */
 		return;
 	}
 
@@ -883,22 +893,23 @@ HandleDeadLock(SIGNAL_ARGS)
 		/* No deadlock, so keep waiting */
 		UnlockLockTable();
 		errno = save_errno;
-		SetWaitingForLock(isWaitingForLock); /* restore waiting status */
 		return;
 	}
 
 	/* ------------------------
-	 * Get this process off the lock's wait queue
+	 * Oops.  We have a deadlock.
+	 *
+	 * Get this process out of wait state.
 	 * ------------------------
 	 */
-	mywaitlock = MyProc->waitLock;
-	Assert(mywaitlock->waitProcs.size > 0);
-	--mywaitlock->waitProcs.size;
-	SHMQueueDelete(&(MyProc->links));
-	SHMQueueElemInit(&(MyProc->links));
-	MyProc->waitLock = NULL;
-	MyProc->waitHolder = NULL;
-	isWaitingForLock = false; /* wait for lock no longer */
+	RemoveFromWaitQueue(MyProc);
+
+	/* -------------
+	 * Set MyProc->errType to STATUS_ERROR so that ProcSleep will
+	 * report an error after we return from this signal handler.
+	 * -------------
+	 */
+	MyProc->errType = STATUS_ERROR;
 
 	/* ------------------
 	 * Unlock my semaphore so that the interrupted ProcSleep() call can finish.
@@ -906,17 +917,16 @@ HandleDeadLock(SIGNAL_ARGS)
 	 */
 	IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum);
 
-	/* -------------
-	 * 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...
+	/* ------------------
+	 * We're done here.  Transaction abort caused by the error that ProcSleep
+	 * will raise will cause any other locks we hold to be released, thus
+	 * allowing other processes to wake up; we don't need to do that here.
+	 * NOTE: an exception is that releasing locks we hold doesn't consider
+	 * the possibility of waiters that were blocked behind us on the lock
+	 * we just failed to get, and might now be wakable because we're not
+	 * in front of them anymore.  However, RemoveFromWaitQueue took care of
+	 * waking up any such processes.
+	 * ------------------
 	 */
 	UnlockLockTable();
 	errno = save_errno;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 1a0aa5d0cdf1c347b83fcccf7f6ef0f4a27e8a56..ff2c0c283d28b6276a48c2c752fc6dc6d097b0e5 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.200 2001/01/12 21:53:59 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.201 2001/01/14 05:08:16 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -84,9 +84,6 @@ bool Log_connections = false;
 
 CommandDest whereToSendOutput = Debug;
 
-
-extern void HandleDeadLock(SIGNAL_ARGS);
-
 static bool	dontExecute = false;
 
 /* note: these declarations had better match tcopprot.h */
@@ -94,7 +91,6 @@ DLLIMPORT sigjmp_buf Warn_restart;
 
 bool		Warn_restart_ready = false;
 bool		InError = false;
-volatile bool ProcDiePending = false;
 
 static bool EchoQuery = false;	/* default don't echo */
 char		pg_pathname[MAXPGPATH];
@@ -732,8 +728,7 @@ pg_exec_query_string(char *query_string,	/* string to execute */
 		}
 
 		/* If we got a cancel signal in parsing or prior command, quit */
-		if (QueryCancel)
-			CancelQuery();
+		CHECK_FOR_INTERRUPTS();
 
 		/*
 		 * OK to analyze and rewrite this query.
@@ -766,8 +761,7 @@ pg_exec_query_string(char *query_string,	/* string to execute */
 			}
 
 			/* If we got a cancel signal in analysis or prior command, quit */
-			if (QueryCancel)
-				CancelQuery();
+			CHECK_FOR_INTERRUPTS();
 
 			if (querytree->commandType == CMD_UTILITY)
 			{
@@ -793,8 +787,7 @@ pg_exec_query_string(char *query_string,	/* string to execute */
 				plan = pg_plan_query(querytree);
 
 				/* if we got a cancel signal whilst planning, quit */
-				if (QueryCancel)
-					CancelQuery();
+				CHECK_FOR_INTERRUPTS();
 
 				/* Initialize snapshot state for query */
 				SetQuerySnapshot();
@@ -898,40 +891,15 @@ finish_xact_command(void)
 
 /* --------------------------------
  *		signal handler routines used in PostgresMain()
- *
- *		handle_warn() catches SIGQUIT.	It forces control back to the main
- *		loop, just as if an internal error (elog(ERROR,...)) had occurred.
- *		elog() used to actually use kill(2) to induce a SIGQUIT to get here!
- *		But that's not 100% reliable on some systems, so now it does its own
- *		siglongjmp() instead.
- *		We still provide the signal catcher so that an error quit can be
- *		forced externally.	This should be done only with great caution,
- *		however, since an asynchronous signal could leave the system in
- *		who-knows-what inconsistent state.
- *
- *		quickdie() occurs when signalled by the postmaster.
- *		Some backend has bought the farm,
- *		so we need to stop what we're doing and exit.
- *
- *		die() performs an orderly cleanup via proc_exit()
  * --------------------------------
  */
 
-void
-handle_warn(SIGNAL_ARGS)
-{
-	/* Don't joggle the elbow of proc_exit */
-	if (proc_exit_inprogress)
-		return;
-	/* Don't joggle the elbow of a critical section, either */
-	if (CritSectionCount > 0)
-	{
-		QueryCancel = true;
-		return;
-	}
-	siglongjmp(Warn_restart, 1);
-}
-
+/*
+ * quickdie() occurs when signalled SIGUSR1 by the postmaster.
+ *
+ * Some backend has bought the farm,
+ * so we need to stop what we're doing and exit.
+ */
 static void
 quickdie(SIGNAL_ARGS)
 {
@@ -943,88 +911,69 @@ quickdie(SIGNAL_ARGS)
 		 " going to terminate your database system connection and exit."
 	"\n\tPlease reconnect to the database system and repeat your query.");
 
-
 	/*
-	 * DO NOT proc_exit(0) -- we're here because shared memory may be
-	 * corrupted, so we don't want to flush any shared state to stable
-	 * storage.  Just nail the windows shut and get out of town.
+	 * DO NOT proc_exit() -- we're here because shared memory may be
+	 * corrupted, so we don't want to try to clean up our transaction.
+	 * Just nail the windows shut and get out of town.
+	 *
+	 * Note we do exit(1) not exit(0).  This is to force the postmaster
+	 * into a system reset cycle if some idiot DBA sends a manual SIGUSR1
+	 * to a random backend.  This is necessary precisely because we don't
+	 * clean up our shared memory state.
 	 */
 
 	exit(1);
 }
 
 /*
- * Abort transaction and exit
+ * Shutdown signal from postmaster: abort transaction and exit
+ * at soonest convenient time
  */
 void
 die(SIGNAL_ARGS)
 {
 	int			save_errno = errno;
 
-	PG_SETMASK(&BlockSig);
-
 	/* Don't joggle the elbow of proc_exit */
-	if (proc_exit_inprogress)
-	{
-		errno = save_errno;
-		return;
-	}
-	/* Don't joggle the elbow of a critical section, either */
-	if (CritSectionCount > 0)
+	if (! proc_exit_inprogress)
 	{
+		InterruptPending = true;
 		ProcDiePending = true;
-		errno = save_errno;
-		return;
+		/*
+		 * If we're waiting for input, service the interrupt immediately
+		 */
+		if (ImmediateInterruptOK && CritSectionCount == 0)
+		{
+			DisableNotifyInterrupt();
+			ProcessInterrupts();
+		}
 	}
-	/* Otherwise force immediate proc_exit */
-	ForceProcDie();
+
+	errno = save_errno;
 }
 
 /*
- * This is split out of die() so that it can be invoked later from
- * END_CRIT_SECTION().
+ * Query-cancel signal from postmaster: abort current transaction
+ * at soonest convenient time
  */
-void
-ForceProcDie(void)
-{
-	/* Reset flag to avoid another elog() during shutdown */
-	ProcDiePending = false;
-	/* Send error message and do proc_exit() */
-	elog(FATAL, "The system is shutting down");
-}
-
-/* signal handler for query cancel signal from postmaster */
 static void
 QueryCancelHandler(SIGNAL_ARGS)
 {
 	int			save_errno = errno;
 
 	/* Don't joggle the elbow of proc_exit, nor an already-in-progress abort */
-	if (proc_exit_inprogress || InError)
+	if (!proc_exit_inprogress && !InError)
 	{
-		errno = save_errno;
-		return;
+		InterruptPending = true;
+		QueryCancelPending = true;
+		/*
+		 * No point in raising Cancel if we are waiting for input ...
+		 */
 	}
 
-	/* Set flag to cause CancelQuery to be called when it's safe */
-	QueryCancel = true;
-
-	/* If we happen to be waiting for a lock, get out of that */
-	LockWaitCancel();
-
-	/* Otherwise, bide our time... */
 	errno = save_errno;
 }
 
-void
-CancelQuery(void)
-{
-	/* Reset flag to avoid another elog() during error recovery */
-	QueryCancel = false;
-	/* Create an artificial error condition to get out of query */
-	elog(ERROR, "Query was cancelled.");
-}
-
 /* signal handler for floating point exception */
 static void
 FloatExceptionHandler(SIGNAL_ARGS)
@@ -1034,6 +983,7 @@ FloatExceptionHandler(SIGNAL_ARGS)
 		 " or was a divide by zero");
 }
 
+/* SIGHUP: set flag to re-read config file at next convenient time */
 static void
 SigHupHandler(SIGNAL_ARGS)
 {
@@ -1041,6 +991,36 @@ SigHupHandler(SIGNAL_ARGS)
 }
 
 
+/*
+ * ProcessInterrupts: out-of-line portion of CHECK_FOR_INTERRUPTS() macro
+ *
+ * If an interrupt condition is pending, and it's safe to service it,
+ * then clear the flag and accept the interrupt.  Called only when
+ * InterruptPending is true.
+ */
+void
+ProcessInterrupts(void)
+{
+	/* Cannot accept interrupts inside critical sections */
+	if (CritSectionCount != 0)
+		return;
+	InterruptPending = false;
+	if (ProcDiePending)
+	{
+		ProcDiePending = false;
+		QueryCancelPending = false;	/* ProcDie trumps QueryCancel */
+		ImmediateInterruptOK = false; /* not idle anymore */
+		elog(FATAL, "The system is shutting down");
+	}
+	if (QueryCancelPending)
+	{
+		QueryCancelPending = false;
+		ImmediateInterruptOK = false; /* not idle anymore */
+		elog(ERROR, "Query was cancelled.");
+	}
+	/* If we get here, do nothing (probably, QueryCancelPending was reset) */
+}
+
 
 static void
 usage(char *progname)
@@ -1502,9 +1482,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
 	 */
 
 	pqsignal(SIGHUP, SigHupHandler);	/* set flag to read config file */
-	pqsignal(SIGINT, QueryCancelHandler);		/* cancel current query */
-	pqsignal(SIGQUIT, handle_warn);		/* handle error */
-	pqsignal(SIGTERM, die);
+	pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */
+	pqsignal(SIGTERM, die);		/* cancel current query and exit */
+	pqsignal(SIGQUIT, die);		/* could reassign this sig for another use */
 	pqsignal(SIGALRM, HandleDeadLock);
 
 	/*
@@ -1517,10 +1497,15 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
 	pqsignal(SIGUSR1, quickdie);
 	pqsignal(SIGUSR2, Async_NotifyHandler);		/* flush also sinval cache */
 	pqsignal(SIGFPE, FloatExceptionHandler);
-	pqsignal(SIGCHLD, SIG_IGN); /* ignored, sent by LockOwners */
+	pqsignal(SIGCHLD, SIG_IGN);	/* ignored (may get this in system() calls) */
+
+	/*
+	 * Reset some signals that are accepted by postmaster but not by backend
+	 */
 	pqsignal(SIGTTIN, SIG_DFL);
 	pqsignal(SIGTTOU, SIG_DFL);
 	pqsignal(SIGCONT, SIG_DFL);
+	pqsignal(SIGWINCH, SIG_DFL);
 
 	pqinitmask();
 
@@ -1683,7 +1668,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
 	if (!IsUnderPostmaster)
 	{
 		puts("\nPOSTGRES backend interactive interface ");
-		puts("$Revision: 1.200 $ $Date: 2001/01/12 21:53:59 $\n");
+		puts("$Revision: 1.201 $ $Date: 2001/01/14 05:08:16 $\n");
 	}
 
 	/*
@@ -1714,6 +1699,16 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
 		 * consider the probability that it should be in AbortTransaction()
 		 * instead.
 		 *
+		 * Make sure we're not interrupted while cleaning up.  Also forget
+		 * any pending QueryCancel request, since we're aborting anyway.
+		 * Force CritSectionCount to a known state in case we elog'd
+		 * from inside a critical section.
+		 */
+		ImmediateInterruptOK = false;
+		QueryCancelPending = false;
+		CritSectionCount = 1;
+
+		/*
 		 * Make sure we are in a valid memory context during recovery.
 		 *
 		 * We use ErrorContext in hopes that it will have some free space
@@ -1738,6 +1733,12 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
 		 * successfully.  (Flag was set in elog.c before longjmp().)
 		 */
 		InError = false;
+
+		/*
+		 * Exit critical section we implicitly established above.
+		 * (This could result in accepting a cancel or die interrupt.)
+		 */
+		END_CRIT_SECTION();
 	}
 
 	Warn_restart_ready = true;	/* we can now handle elog(ERROR) */
@@ -1770,27 +1771,34 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
 		/* ----------------
 		 *	 (2) deal with pending asynchronous NOTIFY from other backends,
 		 *	 and enable async.c's signal handler to execute NOTIFY directly.
+		 *	 Then set up other stuff needed before blocking for input.
 		 * ----------------
 		 */
-		QueryCancel = false;	/* forget any earlier CANCEL signal */
-		SetWaitingForLock(false);
+		QueryCancelPending = false;	/* forget any earlier CANCEL signal */
 
 		EnableNotifyInterrupt();
 
+		set_ps_display("idle");
+
+		/* Allow "die" interrupt to be processed while waiting */
+		ImmediateInterruptOK = true;
+		/* and don't forget to detect one that already arrived */
+		QueryCancelPending = false;
+		CHECK_FOR_INTERRUPTS();
+
 		/* ----------------
 		 *	 (3) read a command (loop blocks here)
 		 * ----------------
 		 */
-		set_ps_display("idle");
-
 		firstchar = ReadCommand(parser_input);
 
-		QueryCancel = false;	/* forget any earlier CANCEL signal */
-
 		/* ----------------
-		 *	 (4) disable async.c's signal handler.
+		 *	 (4) disable async signal conditions again.
 		 * ----------------
 		 */
+		ImmediateInterruptOK = false;
+		QueryCancelPending = false;	/* forget any CANCEL signal */
+
 		DisableNotifyInterrupt();
 
 		/* ----------------
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index b47a628cb1b2284d76c447abec8271f1c7287ba9..460a7175ce57a14cbbbd87c0661e65f3453fdfdd 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.75 2001/01/09 18:40:14 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.76 2001/01/14 05:08:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -120,8 +120,10 @@ elog(int lev, const char *fmt, ...)
 	char	   *msg_buf = msg_fixedbuf;
 	/* this buffer is only used for strange values of lev: */
 	char		prefix_buf[32];
+#ifdef HAVE_SYS_NERR
 	/* this buffer is only used if errno has a bogus value: */
 	char		errorstr_buf[32];
+#endif
 	const char *errorstr;
 	const char *prefix;
 	const char *cp;
@@ -145,17 +147,16 @@ elog(int lev, const char *fmt, ...)
 		errorstr = errorstr_buf;
 	}
 #else
+	/* assume strerror() will cope gracefully with bogus errno values */
     errorstr = strerror(errno);
 #endif
 
-	if (lev == ERROR || lev == FATAL)
-	{
-		/* this is probably redundant... */
-		if (IsInitProcessingMode())
-			lev = FATAL;
-		if (CritSectionCount > 0)
-			lev = STOP;
-	}
+	/* Convert initialization errors into fatal errors.
+	 * This is probably redundant, because Warn_restart_ready won't
+	 * be set anyway...
+	 */
+	if (lev == ERROR && IsInitProcessingMode())
+		lev = FATAL;
 
 	/* choose message prefix and indent level */
 	switch (lev)
@@ -366,8 +367,6 @@ elog(int lev, const char *fmt, ...)
 	if (Debugfile >= 0 && Use_syslog <= 1)
 		write(Debugfile, msg_buf, len);
 
-#ifndef PG_STANDALONE
-
 	if (lev > DEBUG && whereToSendOutput == Remote)
 	{
 		/* Send IPC message to the front-end program */
@@ -424,8 +423,6 @@ elog(int lev, const char *fmt, ...)
 			fputs(msg_buf, stderr);
 	}
 
-#endif	 /* !PG_STANDALONE */
-
 	/* done with the message, release space */
 	if (fmt_buf != fmt_fixedbuf)
 		free(fmt_buf);
@@ -437,6 +434,8 @@ elog(int lev, const char *fmt, ...)
 	 */
 	if (lev == ERROR || lev == FATAL)
 	{
+		/* Prevent immediate interrupt while entering error recovery */
+		ImmediateInterruptOK = false;
 
 		/*
 		 * For a FATAL error, we let proc_exit clean up and exit.
@@ -477,7 +476,6 @@ elog(int lev, const char *fmt, ...)
 
 	if (lev > FATAL)
 	{
-
 		/*
 		 * Serious crash time. Postmaster will observe nonzero process
 		 * exit status and kill the other backends too.
@@ -485,6 +483,7 @@ elog(int lev, const char *fmt, ...)
 		 * XXX: what if we are *in* the postmaster?  proc_exit() won't kill
 		 * our children...
 		 */
+		ImmediateInterruptOK = false;
 		fflush(stdout);
 		fflush(stderr);
 		proc_exit(lev);
@@ -493,8 +492,6 @@ elog(int lev, const char *fmt, ...)
 	/* We reach here if lev <= NOTICE.	OK to return to caller. */
 }
 
-#ifndef PG_STANDALONE
-
 int
 DebugFileOpen(void)
 {
@@ -556,9 +553,6 @@ DebugFileOpen(void)
 	return Debugfile;
 }
 
-#endif
-
-
 
 /*
  * Return a timestamp string like
@@ -602,6 +596,10 @@ print_pid(void)
 
 #ifdef ENABLE_SYSLOG
 
+#ifndef PG_SYSLOG_LIMIT
+# define PG_SYSLOG_LIMIT 128
+#endif
+
 /*
  * Write a message line to syslog if the syslog option is set.
  *
@@ -613,10 +611,6 @@ print_pid(void)
 static void
 write_syslog(int level, const char *line)
 {
-#ifndef PG_SYSLOG_LIMIT
-# define PG_SYSLOG_LIMIT 128
-#endif
-
 	static bool	openlog_done = false;
 	static unsigned long seq = 0;
 	static int	syslog_fac = LOG_LOCAL0;
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 4359ef60a88f3d874bfc30e7b336cf67223bff9e..8e9d4c95db09d70124f207345035f1e46c14eb7e 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.49 2001/01/07 04:17:29 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.50 2001/01/14 05:08:16 tgl Exp $
  *
  * NOTES
  *	  Globals used all over the place should be declared here and not
@@ -34,7 +34,12 @@ ProtocolVersion FrontendProtocol = PG_PROTOCOL_LATEST;
 
 bool		Noversion = false;
 bool		Quiet = false;
-volatile bool QueryCancel = false;
+
+volatile bool InterruptPending = false;
+volatile bool QueryCancelPending = false;
+volatile bool ProcDiePending = false;
+volatile bool ImmediateInterruptOK = false;
+volatile uint32 CritSectionCount = 0;
 
 int			MyProcPid;
 struct Port *MyProcPort;
@@ -56,9 +61,7 @@ BackendId	MyBackendId;
 char	   *DatabaseName = NULL;
 char	   *DatabasePath = NULL;
 
-bool		MyDatabaseIdIsInitialized = false;
 Oid			MyDatabaseId = InvalidOid;
-bool		TransactionInitWasProcessed = false;
 
 bool		IsUnderPostmaster = false;
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 7736ec92e8733b88cc4139c1b6eff98285de0535..47e14c3a8272b3af6d72b85540e3ad37c47ec652 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -3,7 +3,7 @@
  *
  * PostgreSQL transaction log manager
  *
- * $Header: /cvsroot/pgsql/src/include/access/xlog.h,v 1.16 2001/01/12 21:54:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/include/access/xlog.h,v 1.17 2001/01/14 05:08:16 tgl Exp $
  */
 #ifndef XLOG_H
 #define XLOG_H
@@ -101,7 +101,6 @@ typedef XLogPageHeaderData *XLogPageHeader;
 extern	StartUpID	ThisStartUpID;	/* current SUI */
 extern	bool		InRecovery;
 extern	XLogRecPtr	MyLastRecPtr;
-extern volatile uint32		CritSectionCount;
 
 typedef struct RmgrData
 {
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 6b5dff9478ad6c4e1bf8529a399539e09f2a2cb8..39410abe1386ece282aa5c3277f7c411f85714c0 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -12,10 +12,10 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: miscadmin.h,v 1.76 2001/01/07 04:17:28 tgl Exp $
+ * $Id: miscadmin.h,v 1.77 2001/01/14 05:08:16 tgl Exp $
  *
  * NOTES
- *	  some of the information in this file will be moved to
+ *	  some of the information in this file should be moved to
  *	  other files.
  *
  *-------------------------------------------------------------------------
@@ -23,11 +23,63 @@
 #ifndef MISCADMIN_H
 #define MISCADMIN_H
 
-#include <sys/types.h>			/* For pid_t */
-
-#include "postgres.h"
 #include "storage/ipc.h"
 
+/*****************************************************************************
+ *    System interrupt handling
+ *
+ * There are two types of interrupts that a running backend needs to accept
+ * without messing up its state: QueryCancel (SIGINT) and ProcDie (SIGTERM).
+ * In both cases, we need to be able to clean up the current transaction
+ * gracefully, so we can't respond to the interrupt instantaneously ---
+ * there's no guarantee that internal data structures would be self-consistent
+ * if the code is interrupted at an arbitrary instant.  Instead, the signal
+ * handlers set flags that are checked periodically during execution.
+ *
+ * The CHECK_FOR_INTERRUPTS() macro is called at strategically located spots
+ * where it is normally safe to accept a cancel or die interrupt.  In some
+ * cases, we invoke CHECK_FOR_INTERRUPTS() inside low-level subroutines that
+ * might sometimes be called in contexts that do *not* want to allow a cancel
+ * or die interrupt.  The CRIT_SECTION mechanism allows code to ensure that
+ * no cancel or die interrupt will be accepted, even if CHECK_FOR_INTERRUPTS
+ * gets called in a subroutine.
+ *
+ * Special mechanisms are used to let an interrupt be accepted when we are
+ * waiting for a lock or spinlock, and when we are waiting for command input
+ * (but, of course, only if the critical section counter is zero).  See the
+ * related code for details.
+ *
+ *****************************************************************************/
+
+/* in globals.c */
+/* these are marked volatile because they are set by signal handlers: */
+extern volatile bool InterruptPending;
+extern volatile bool QueryCancelPending;
+extern volatile bool ProcDiePending;
+/* these are marked volatile because they are examined by signal handlers: */
+extern volatile bool ImmediateInterruptOK;
+extern volatile uint32 CritSectionCount;
+
+/* in postgres.c */
+extern void ProcessInterrupts(void);
+
+#define CHECK_FOR_INTERRUPTS() \
+	do { \
+		if (InterruptPending) \
+			ProcessInterrupts(); \
+	} while(0)
+
+#define	START_CRIT_SECTION()  (CritSectionCount++)
+
+#define END_CRIT_SECTION() \
+	do { \
+		Assert(CritSectionCount > 0); \
+		CritSectionCount--; \
+		if (CritSectionCount == 0 && InterruptPending) \
+			ProcessInterrupts(); \
+	} while(0)
+
+
 /*****************************************************************************
  *	  globals.h --															 *
  *****************************************************************************/
@@ -42,7 +94,6 @@ extern int	PostmasterMain(int argc, char *argv[]);
  */
 extern bool Noversion;
 extern bool Quiet;
-extern volatile bool QueryCancel;
 extern char *DataDir;
 
 extern int	MyProcPid;
@@ -56,9 +107,7 @@ extern char OutputFileName[];
  *
  * extern BackendId    MyBackendId;
  */
-extern bool MyDatabaseIdIsInitialized;
 extern Oid	MyDatabaseId;
-extern bool TransactionInitWasProcessed;
 
 extern bool IsUnderPostmaster;
 
@@ -143,7 +192,8 @@ extern void SetSessionUserIdFromUserName(const char *username);
 
 extern void SetDataDir(const char *dir);
 
-extern int	FindExec(char *full_path, const char *argv0, const char *binary_name);
+extern int	FindExec(char *full_path, const char *argv0,
+					 const char *binary_name);
 extern int	CheckPathAccess(char *path, char *name, int open_mode);
 
 #ifdef CYR_RECODE
@@ -157,17 +207,17 @@ extern char *convertstr(unsigned char *buff, int len, int dest);
 /*
  * Description:
  *		There are three processing modes in POSTGRES.  They are
- * "BootstrapProcessing or "bootstrap," InitProcessing or
+ * BootstrapProcessing or "bootstrap," InitProcessing or
  * "initialization," and NormalProcessing or "normal."
  *
  * The first two processing modes are used during special times. When the
  * system state indicates bootstrap processing, transactions are all given
- * transaction id "one" and are consequently guarenteed to commit. This mode
+ * transaction id "one" and are consequently guaranteed to commit. This mode
  * is used during the initial generation of template databases.
  *
- * Initialization mode until all normal initialization is complete.
- * Some code behaves differently when executed in this mode to enable
- * system bootstrapping.
+ * Initialization mode: used while starting a backend, until all normal
+ * initialization is complete.  Some code behaves differently when executed
+ * in this mode to enable system bootstrapping.
  *
  * If a POSTGRES binary is in normal mode, then all code may be executed
  * normally.
@@ -185,27 +235,13 @@ typedef enum ProcessingMode
  *	  pinit.h --															 *
  *			POSTGRES initialization and cleanup definitions.				 *
  *****************************************************************************/
-/*
- * Note:
- *		XXX AddExitHandler not defined yet.
- */
-
-typedef int16 ExitStatus;
-
-#define NormalExitStatus		(0)
-#define FatalExitStatus			(127)
-/* XXX are there any other meaningful exit codes? */
 
 /* in utils/init/postinit.c */
-
 extern int	lockingOff;
 
 extern void InitPostgres(const char *dbname, const char *username);
 extern void BaseInit(void);
 
-/* one of the ways to get out of here */
-#define ExitPostgres(status) proc_exec(status)
-
 /* processing mode support stuff */
 extern ProcessingMode Mode;
 
@@ -215,21 +251,22 @@ extern ProcessingMode Mode;
 
 #define SetProcessingMode(mode) \
 	do { \
-		AssertArg(mode == BootstrapProcessing || mode == InitProcessing || \
-				  mode == NormalProcessing); \
-		Mode = mode; \
+		AssertArg((mode) == BootstrapProcessing || \
+				  (mode) == InitProcessing || \
+				  (mode) == NormalProcessing); \
+		Mode = (mode); \
 	} while(0)
 
 #define GetProcessingMode() Mode
 
-extern void IgnoreSystemIndexes(bool mode);
-extern bool IsIgnoringSystemIndexes(void);
-extern bool IsCacheInitialized(void);
-extern void SetWaitingForLock(bool);
-
 extern bool CreateDataDirLockFile(const char *datadir, bool amPostmaster);
 extern bool CreateSocketLockFile(const char *socketfile, bool amPostmaster);
 
 extern void ValidatePgVersion(const char *path);
 
+/* these externs do not belong here... */
+extern void IgnoreSystemIndexes(bool mode);
+extern bool IsIgnoringSystemIndexes(void);
+extern bool IsCacheInitialized(void);
+
 #endif	 /* MISCADMIN_H */
diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h
index 55aa29635875b8f830a8323fca3b69fa73f74548..ca8f827d4f91b70bc61be015f206a34439779573 100644
--- a/src/include/storage/ipc.h
+++ b/src/include/storage/ipc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: ipc.h,v 1.44 2000/12/03 17:18:09 tgl Exp $
+ * $Id: ipc.h,v 1.45 2001/01/14 05:08:16 tgl Exp $
  *
  * Some files that would normally need to include only sys/ipc.h must
  * instead include this file because on Ultrix, sys/ipc.h is not designed
@@ -99,7 +99,7 @@ extern IpcSemaphoreId IpcSemaphoreCreate(int numSems, int permission,
 										 int semStartValue,
 										 bool removeOnExit);
 extern void IpcSemaphoreKill(IpcSemaphoreId semId);
-extern void IpcSemaphoreLock(IpcSemaphoreId semId, int sem);
+extern void IpcSemaphoreLock(IpcSemaphoreId semId, int sem, bool interruptOK);
 extern void IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem);
 extern bool IpcSemaphoreTryLock(IpcSemaphoreId semId, int sem);
 extern int	IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 96928eb452845eb0ac097f79545da4348229fd24..65308d71adaf525f7716eb2245266922cda1b280 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: proc.h,v 1.33 2000/12/22 00:51:54 tgl Exp $
+ * $Id: proc.h,v 1.34 2001/01/14 05:08:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,9 +22,8 @@ extern int DeadlockTimeout;
 
 typedef struct
 {
-	int			sleeplock;
-	IpcSemaphoreId semId;
-	int			semNum;
+	IpcSemaphoreId semId;		/* SysV semaphore set ID */
+	int			semNum;			/* semaphore number within set */
 } SEMA;
 
 /*
@@ -38,12 +37,6 @@ struct proc
 	SEMA		sem;			/* ONE semaphore to sleep on */
 	int			errType;		/* error code tells why we woke up */
 
-	int			critSects;		/* If critSects > 0, we are in sensitive
-								 * routines that cannot be recovered when
-								 * the process fails. */
-
-	int			prio;			/* priority for sleep queue */
-
 	TransactionId xid;			/* transaction currently being executed by
 								 * this proc */
 
@@ -72,6 +65,9 @@ struct proc
 
 extern PROC *MyProc;
 
+extern SPINLOCK ProcStructLock;
+
+
 #define PROC_INCR_SLOCK(lock) \
 do { \
 	if (MyProc) (MyProc->sLocks[(lock)])++; \
@@ -89,11 +85,6 @@ do { \
 #define ERR_TIMEOUT		1
 #define ERR_BUFFER_IO	2
 
-#define MAX_PRIO		50
-#define MIN_PRIO		(-1)
-
-extern SPINLOCK ProcStructLock;
-
 
 /*
  * There is one ProcGlobal struct for the whole installation.
@@ -142,5 +133,6 @@ extern int ProcLockWakeup(LOCKMETHOD lockmethod, LOCK *lock);
 extern void ProcAddLock(SHM_QUEUE *elem);
 extern void ProcReleaseSpins(PROC *proc);
 extern void LockWaitCancel(void);
+extern void HandleDeadLock(SIGNAL_ARGS);
 
 #endif	 /* PROC_H */
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index 0b97397d7ca74fc393b46dd435959a9066e1de56..d7b7ff768506e634c113cd75cbce4f1adf154e92 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: tcopprot.h,v 1.36 2000/12/03 10:27:29 vadim Exp $
+ * $Id: tcopprot.h,v 1.37 2001/01/14 05:08:16 tgl Exp $
  *
  * OLD COMMENTS
  *	  This file was created so that other c files could get the two
@@ -40,9 +40,7 @@ extern void pg_exec_query_string(char *query_string,
 
 #endif	 /* BOOTSTRAP_INCLUDE */
 
-extern void handle_warn(SIGNAL_ARGS);
 extern void die(SIGNAL_ARGS);
-extern void CancelQuery(void);
 extern int PostgresMain(int argc, char *argv[],
 			 int real_argc, char *real_argv[], const char *username);
 extern void ResetUsage(void);
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index da9178b2767f3d41f5e0344bea37941b3ad542f4..8468118177fd6ce79168d78d1b09e2dcb32e4746 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -7,13 +7,14 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: elog.h,v 1.23 2001/01/12 21:54:01 tgl Exp $
+ * $Id: elog.h,v 1.24 2001/01/14 05:08:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef ELOG_H
 #define ELOG_H
 
+/* Error level codes */
 #define NOTICE	0				/* random info - no special action */
 #define ERROR	(-1)			/* user error - return to known state */
 #define FATAL	1				/* fatal error - abort process */
@@ -23,47 +24,25 @@
 #define LOG		DEBUG
 #define NOIND	(-3)			/* debug message, don't indent as far */
 
+/* Configurable parameters */
 #ifdef ENABLE_SYSLOG
 extern int Use_syslog;
 #endif
-
-/*
- * If CritSectionCount > 0, signal handlers mustn't do
- * elog(ERROR|FATAL), instead remember what action is
- * required with QueryCancel or ProcDiePending.
- * ProcDiePending will be honored at critical section exit,
- * but QueryCancel is only checked at specified points.
- */
-extern volatile uint32 CritSectionCount;	/* duplicates access/xlog.h */
-extern volatile bool ProcDiePending;
-extern void ForceProcDie(void);	/* in postgres.c */
-
-#define	START_CRIT_SECTION()  (CritSectionCount++)
-
-#define END_CRIT_SECTION() \
-	do { \
-		Assert(CritSectionCount > 0); \
-		CritSectionCount--; \
-		if (CritSectionCount == 0 && ProcDiePending) \
-			ForceProcDie(); \
-	} while(0)
-
 extern bool Log_timestamp;
 extern bool Log_pid;
 
+
 #ifndef __GNUC__
-extern void elog(int lev, const char *fmt,...);
+extern void elog(int lev, const char *fmt, ...);
 
 #else
 /* This extension allows gcc to check the format string for consistency with
    the supplied arguments. */
-extern void elog(int lev, const char *fmt,...) __attribute__((format(printf, 2, 3)));
+extern void elog(int lev, const char *fmt, ...)
+	__attribute__((format(printf, 2, 3)));
 
 #endif
 
-#ifndef PG_STANDALONE
 extern int	DebugFileOpen(void);
 
-#endif
-
 #endif	 /* ELOG_H */
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index 7fe527293f4beacc75d8c1cfb24c630fa69aed9e..1bfb406ac56ae77a85ed22c66bb736b652f8749a 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -12,10 +12,12 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.70 2000/12/15 20:01:55 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.71 2001/01/14 05:08:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
+#include "postgres.h"
+
 #include <ctype.h>
 #include <sys/types.h>
 #include <limits.h>