diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index a8b7b4ec1bc2cfe87c9d50c7bdcea4f747877fd4..a73ba4df4abc1ba33cad7356e0c9f114f044998c 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.198 2000/12/20 21:51:52 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.199 2001/01/07 04:17:29 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -94,7 +94,7 @@ DLLIMPORT sigjmp_buf Warn_restart;
 
 bool		Warn_restart_ready = false;
 bool		InError = false;
-bool		ProcDiePending = false;
+volatile bool ProcDiePending = false;
 
 static bool EchoQuery = false;	/* default don't echo */
 char		pg_pathname[MAXPGPATH];
@@ -920,7 +920,10 @@ finish_xact_command(void)
 void
 handle_warn(SIGNAL_ARGS)
 {
-	/* Don't joggle the elbow of a critical section */
+	/* 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;
@@ -956,28 +959,38 @@ quickdie(SIGNAL_ARGS)
 void
 die(SIGNAL_ARGS)
 {
+	int			save_errno = errno;
+
 	PG_SETMASK(&BlockSig);
 
-	/* Don't joggle the elbow of a critical section */
+	/* 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)
 	{
-		QueryCancel = true;
 		ProcDiePending = true;
+		errno = save_errno;
 		return;
 	}
-	/* Don't joggle the elbow of proc_exit, either */
-	if (proc_exit_inprogress)
-		return;
-	elog(FATAL, "The system is shutting down");
+	/* Otherwise force immediate proc_exit */
+	ForceProcDie();
 }
 
-/* signal handler for floating point exception */
-static void
-FloatExceptionHandler(SIGNAL_ARGS)
+/*
+ * This is split out of die() so that it can be invoked later from
+ * END_CRIT_CODE.
+ */
+void
+ForceProcDie(void)
 {
-	elog(ERROR, "floating point exception!"
-		 " The last floating point operation either exceeded legal ranges"
-		 " or was a divide by zero");
+	/* 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 */
@@ -986,22 +999,41 @@ 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)
+	{
+		errno = save_errno;
+		return;
+	}
+
+	/* 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)
 {
-
-	/*
-	 * QueryCancel flag will be reset in main loop, which we reach by
-	 * longjmp from elog().
-	 */
+	/* 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)
+{
+	elog(ERROR, "floating point exception!"
+		 " The last floating point operation either exceeded legal ranges"
+		 " or was a divide by zero");
+}
+
 static void
 SigHupHandler(SIGNAL_ARGS)
 {
@@ -1651,7 +1683,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
 	if (!IsUnderPostmaster)
 	{
 		puts("\nPOSTGRES backend interactive interface ");
-		puts("$Revision: 1.198 $ $Date: 2000/12/20 21:51:52 $\n");
+		puts("$Revision: 1.199 $ $Date: 2001/01/07 04:17:29 $\n");
 	}
 
 	/*
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index e6b57c648b374b0375d330ecfb82417a9834267e..4359ef60a88f3d874bfc30e7b336cf67223bff9e 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.48 2000/12/28 13:00:24 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.49 2001/01/07 04:17:29 tgl Exp $
  *
  * NOTES
  *	  Globals used all over the place should be declared here and not
@@ -34,7 +34,7 @@ ProtocolVersion FrontendProtocol = PG_PROTOCOL_LATEST;
 
 bool		Noversion = false;
 bool		Quiet = false;
-bool		QueryCancel = false;
+volatile bool QueryCancel = false;
 
 int			MyProcPid;
 struct Port *MyProcPort;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index f41a01822ac8b3e04f863e3ee8dfb8b82857f8d3..6b5dff9478ad6c4e1bf8529a399539e09f2a2cb8 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: miscadmin.h,v 1.75 2000/11/29 20:59:54 tgl Exp $
+ * $Id: miscadmin.h,v 1.76 2001/01/07 04:17:28 tgl Exp $
  *
  * NOTES
  *	  some of the information in this file will be moved to
@@ -42,7 +42,7 @@ extern int	PostmasterMain(int argc, char *argv[]);
  */
 extern bool Noversion;
 extern bool Quiet;
-extern bool QueryCancel;
+extern volatile bool QueryCancel;
 extern char *DataDir;
 
 extern int	MyProcPid;
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 37db2c7aaf84c5e3025af0805f40dd90606fb4d1..e7305d67fc266bd18df746530de43508c3f938d7 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: elog.h,v 1.21 2000/12/18 00:44:50 tgl Exp $
+ * $Id: elog.h,v 1.22 2001/01/07 04:17:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,11 +30,13 @@ extern int Use_syslog;
 /*
  * If CritSectionCount > 0, signal handlers mustn't do
  * elog(ERROR|FATAL), instead remember what action is
- * required with QueryCancel & ProcDiePending.
+ * required with QueryCancel or ProcDiePending.
+ * ProcDiePending will be honored at critical section exit,
+ * but QueryCancel is only checked at specified points.
  */
 extern uint32 CritSectionCount;	/* duplicates access/xlog.h */
-extern bool QueryCancel;		/* duplicates miscadmin.h */
-extern bool	ProcDiePending;
+extern volatile bool ProcDiePending;
+extern void ForceProcDie(void);	/* in postgres.c */
 
 #define	START_CRIT_CODE		(CritSectionCount++)
 
@@ -43,13 +45,8 @@ extern bool	ProcDiePending;
 		if (CritSectionCount == 0) \
 			elog(STOP, "Not in critical section"); \
 		CritSectionCount--; \
-		if (CritSectionCount == 0 && QueryCancel) \
-		{ \
-			if (ProcDiePending) \
-				elog(FATAL, "The system is shutting down"); \
-			else \
-				elog(ERROR, "Query was cancelled."); \
-		} \
+		if (CritSectionCount == 0 && ProcDiePending) \
+			ForceProcDie(); \
 	} while(0)
 
 extern bool Log_timestamp;