Restructure backend SIGINT/SIGTERM handling so that 'die' interrupts
authorTom Lane
Sun, 14 Jan 2001 05:08:17 +0000 (05:08 +0000)
committerTom Lane
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 
 #include 
 
+#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 
 #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          /* 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 
 #include 
 #include