]> granicus.if.org Git - postgresql/commitdiff
Restructure backend SIGINT/SIGTERM handling so that 'die' interrupts
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 14 Jan 2001 05:08:17 +0000 (05:08 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 14 Jan 2001 05:08:17 +0000 (05:08 +0000)
are treated more like 'cancel' interrupts: the signal handler sets a
flag that is examined at well-defined spots, rather than trying to cope
with an interrupt that might happen anywhere.  See pghackers discussion
of 1/12/01.

24 files changed:
src/backend/access/nbtree/nbtinsert.c
src/backend/access/transam/xact.c
src/backend/access/transam/xlog.c
src/backend/bootstrap/bootstrap.c
src/backend/commands/analyze.c
src/backend/commands/copy.c
src/backend/commands/vacuum.c
src/backend/executor/execProcnode.c
src/backend/storage/buffer/bufmgr.c
src/backend/storage/buffer/s_lock.c
src/backend/storage/ipc/ipc.c
src/backend/storage/ipc/spin.c
src/backend/storage/lmgr/lock.c
src/backend/storage/lmgr/proc.c
src/backend/tcop/postgres.c
src/backend/utils/error/elog.c
src/backend/utils/init/globals.c
src/include/access/xlog.h
src/include/miscadmin.h
src/include/storage/ipc.h
src/include/storage/proc.h
src/include/tcop/tcopprot.h
src/include/utils/elog.h
src/interfaces/ecpg/preproc/pgc.l

index 1aae86c00257918a258eed8ceec5d14d999d63d1..852a457e2a5557a97f51950f675e4e292319b3e0 100644 (file)
@@ -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
index e3f4a5618f7a3b6decd36fe361af4e84b01fdd6d..e79ada35426e36617e696f1df6a78ba03c70055c 100644 (file)
@@ -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();
 }
 
 /* --------------------------------
index e995b06f914f76a5473b43d3bc4510ea15dce820..5777e035d4626773944ed3c0cad4b42d44535c02 100644 (file)
@@ -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;
index cd4186eec83668304a2342d79ac07580fca830ab..19b421a51d4f6d251fb6f5b2578ebab876fd10f5 100644 (file)
@@ -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++;
index a1dee895b3fd16336f51522d89217220dd9da21d..889cd5316e81156142cc1ff99c34219aec6f26ca 100644 (file)
@@ -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
index f33c6e9eb4c85a3383ff93dbf9a0932c76fe79b9..25f6bace81e6925a5b430eb86eab3597c7c8aed4 100644 (file)
@@ -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++;
 
index 76425652b9703b134062cbc38b6508e8a05e1052..2a402004ca0870a970605c51aa537033049374f6 100644 (file)
@@ -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
index d7db099653dccaf66af1f4ee5fcc8696e6b8d7aa..6cc2a1aed97e605b29851071c09ebbda9c09c38f 100644 (file)
@@ -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;
 
index 2be519193bbf6fb253fff99d4f3a65ac9f1966be..6b897588621ade9c8e4e07ac4bf137c9e506ec3b 100644 (file)
@@ -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;
index 932e5b0049b9dcfc41a155d170c4065c15d9e9da..00a934c38321f1c4eb9d953af37489c65a9dd084 100644 (file)
@@ -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();
        }
 }
 
index d592a17986702c763876800fb89d2548a5115888..9d796299dc6af293040a63a1735b49f6a1c6d0a1 100644 (file)
@@ -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)
index ed71d79ad9f3cb7b278e502a4a44377f3bc37d3d..b27c181002025b27122bdb8ae1defc4e019bb0c3 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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();
index f15ee9f8bd6f0492faf25313da168ce08cfc63b4..e7d1b678bef61e4655a89505259fb46d0c1ac1ed 100644 (file)
@@ -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);
index baa31413e2fefd5c8ebda9a81f39b8c0246c74b8..b5a22bb2321b5032b3f54bd06e52150fe56f8141 100644 (file)
@@ -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"
 
 #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;
index 1a0aa5d0cdf1c347b83fcccf7f6ef0f4a27e8a56..ff2c0c283d28b6276a48c2c752fc6dc6d097b0e5 100644 (file)
@@ -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();
 
                /* ----------------
index b47a628cb1b2284d76c447abec8271f1c7287ba9..460a7175ce57a14cbbbd87c0661e65f3453fdfdd 100644 (file)
@@ -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;
index 4359ef60a88f3d874bfc30e7b336cf67223bff9e..8e9d4c95db09d70124f207345035f1e46c14eb7e 100644 (file)
@@ -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;
 
index 7736ec92e8733b88cc4139c1b6eff98285de0535..47e14c3a8272b3af6d72b85540e3ad37c47ec652 100644 (file)
@@ -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
 {
index 6b5dff9478ad6c4e1bf8529a399539e09f2a2cb8..39410abe1386ece282aa5c3277f7c411f85714c0 100644 (file)
  * 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.
  *
  *-------------------------------------------------------------------------
 #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 */
index 55aa29635875b8f830a8323fca3b69fa73f74548..ca8f827d4f91b70bc61be015f206a34439779573 100644 (file)
@@ -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);
index 96928eb452845eb0ac097f79545da4348229fd24..65308d71adaf525f7716eb2245266922cda1b280 100644 (file)
@@ -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 */
index 0b97397d7ca74fc393b46dd435959a9066e1de56..d7b7ff768506e634c113cd75cbce4f1adf154e92 100644 (file)
@@ -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);
index da9178b2767f3d41f5e0344bea37941b3ad542f4..8468118177fd6ce79168d78d1b09e2dcb32e4746 100644 (file)
@@ -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 */
 #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 */
index 7fe527293f4beacc75d8c1cfb24c630fa69aed9e..1bfb406ac56ae77a85ed22c66bb736b652f8749a 100644 (file)
  *
  *
  * 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>