Commit 36839c19 authored by Tom Lane's avatar Tom Lane

Restructure backend SIGINT/SIGTERM handling so that 'die' interrupts

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.
parent 027f144e
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -17,6 +17,7 @@
#include "access/heapam.h" #include "access/heapam.h"
#include "access/nbtree.h" #include "access/nbtree.h"
#include "miscadmin.h"
typedef struct typedef struct
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Transaction aborts can now occur two ways: * Transaction aborts can now occur two ways:
...@@ -1015,6 +1015,9 @@ CommitTransaction(void) ...@@ -1015,6 +1015,9 @@ CommitTransaction(void)
if (s->state != TRANS_INPROGRESS) if (s->state != TRANS_INPROGRESS)
elog(NOTICE, "CommitTransaction and not in in-progress state "); 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 * Tell the trigger manager that this transaction is about to be
* committed. He'll invoke all trigger deferred until XACT before * committed. He'll invoke all trigger deferred until XACT before
...@@ -1083,6 +1086,8 @@ CommitTransaction(void) ...@@ -1083,6 +1086,8 @@ CommitTransaction(void)
* ---------------- * ----------------
*/ */
s->state = TRANS_DEFAULT; s->state = TRANS_DEFAULT;
END_CRIT_SECTION();
} }
/* -------------------------------- /* --------------------------------
...@@ -1095,6 +1100,9 @@ AbortTransaction(void) ...@@ -1095,6 +1100,9 @@ AbortTransaction(void)
{ {
TransactionState s = CurrentTransactionState; TransactionState s = CurrentTransactionState;
/* Prevent cancel/die interrupt while cleaning up */
START_CRIT_SECTION();
/* /*
* Let others to know about no transaction in progress - vadim * Let others to know about no transaction in progress - vadim
* 11/26/96 * 11/26/96
...@@ -1113,13 +1121,21 @@ AbortTransaction(void) ...@@ -1113,13 +1121,21 @@ AbortTransaction(void)
*/ */
ProcReleaseSpins(NULL); ProcReleaseSpins(NULL);
UnlockBuffers(); 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 * check the current transaction state
* ---------------- * ----------------
*/ */
if (s->state == TRANS_DISABLED) if (s->state == TRANS_DISABLED)
{
END_CRIT_SECTION();
return; return;
}
if (s->state != TRANS_INPROGRESS) if (s->state != TRANS_INPROGRESS)
elog(NOTICE, "AbortTransaction and not in in-progress state"); elog(NOTICE, "AbortTransaction and not in in-progress state");
...@@ -1169,6 +1185,7 @@ AbortTransaction(void) ...@@ -1169,6 +1185,7 @@ AbortTransaction(void)
* State remains TRANS_ABORT until CleanupTransaction(). * State remains TRANS_ABORT until CleanupTransaction().
* ---------------- * ----------------
*/ */
END_CRIT_SECTION();
} }
/* -------------------------------- /* --------------------------------
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -42,7 +42,6 @@
int XLOGbuffers = 8; int XLOGbuffers = 8;
int XLOGfiles = 0; /* how many files to pre-allocate */ int XLOGfiles = 0; /* how many files to pre-allocate */
XLogRecPtr MyLastRecPtr = {0, 0}; XLogRecPtr MyLastRecPtr = {0, 0};
volatile uint32 CritSectionCount = 0;
bool InRecovery = false; bool InRecovery = false;
StartUpID ThisStartUpID = 0; StartUpID ThisStartUpID = 0;
XLogRecPtr RedoRecPtr; XLogRecPtr RedoRecPtr;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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[]) ...@@ -329,9 +329,10 @@ BootstrapMain(int argc, char *argv[])
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
pqsignal(SIGINT, (pqsigfunc) die); pqsignal(SIGHUP, die);
pqsignal(SIGHUP, (pqsigfunc) die); pqsignal(SIGINT, die);
pqsignal(SIGTERM, (pqsigfunc) die); pqsignal(SIGTERM, die);
pqsignal(SIGQUIT, die);
} }
/* /*
...@@ -383,8 +384,6 @@ BootstrapMain(int argc, char *argv[]) ...@@ -383,8 +384,6 @@ BootstrapMain(int argc, char *argv[])
* abort processing resumes here * abort processing resumes here
* ---------------- * ----------------
*/ */
pqsignal(SIGHUP, handle_warn);
if (sigsetjmp(Warn_restart, 1) != 0) if (sigsetjmp(Warn_restart, 1) != 0)
{ {
Warnings++; Warnings++;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -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 * Check for user-requested abort. Note we want this to be inside a
* transaction, so xact.c doesn't issue useless NOTICE. * transaction, so xact.c doesn't issue useless NOTICE.
*/ */
if (QueryCancel) CHECK_FOR_INTERRUPTS();
CancelQuery();
/* /*
* Race condition -- if the pg_class tuple has gone away since the * Race condition -- if the pg_class tuple has gone away since the
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -449,8 +449,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
{ {
bool need_delim = false; bool need_delim = false;
if (QueryCancel) CHECK_FOR_INTERRUPTS();
CancelQuery();
if (binary) if (binary)
{ {
...@@ -702,11 +701,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, ...@@ -702,11 +701,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
while (!done) while (!done)
{ {
if (QueryCancel) CHECK_FOR_INTERRUPTS();
{
lineno = 0;
CancelQuery();
}
lineno++; lineno++;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -378,8 +378,7 @@ vacuum_rel(Oid relid)
* Check for user-requested abort. Note we want this to be inside a * Check for user-requested abort. Note we want this to be inside a
* transaction, so xact.c doesn't issue useless NOTICE. * transaction, so xact.c doesn't issue useless NOTICE.
*/ */
if (QueryCancel) CHECK_FOR_INTERRUPTS();
CancelQuery();
/* /*
* Race condition -- if the pg_class tuple has gone away since the * Race condition -- if the pg_class tuple has gone away since the
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -248,14 +248,12 @@ ExecProcNode(Plan *node, Plan *parent)
{ {
TupleTableSlot *result; TupleTableSlot *result;
CHECK_FOR_INTERRUPTS();
/* ---------------- /* ----------------
* deal with NULL nodes.. * deal with NULL nodes..
* ---------------- * ----------------
*/ */
if (QueryCancel)
CancelQuery();
if (node == NULL) if (node == NULL)
return NULL; return NULL;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -92,6 +92,7 @@ static Buffer ReadBufferWithBufferLock(Relation relation, BlockNumber blockNum,
bool bufferLockHeld); bool bufferLockHeld);
static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum, static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
bool *foundPtr, bool bufferLockHeld); bool *foundPtr, bool bufferLockHeld);
static int ReleaseBufferWithBufferLock(Buffer buffer);
static int BufferReplace(BufferDesc *bufHdr); static int BufferReplace(BufferDesc *bufHdr);
void PrintBufferDescs(void); void PrintBufferDescs(void);
...@@ -687,10 +688,14 @@ ReleaseAndReadBuffer(Buffer buffer, ...@@ -687,10 +688,14 @@ ReleaseAndReadBuffer(Buffer buffer,
{ {
bufHdr = &BufferDescriptors[buffer - 1]; bufHdr = &BufferDescriptors[buffer - 1];
Assert(PrivateRefCount[buffer - 1] > 0); Assert(PrivateRefCount[buffer - 1] > 0);
PrivateRefCount[buffer - 1]--; if (PrivateRefCount[buffer - 1] > 1)
if (PrivateRefCount[buffer - 1] == 0) {
PrivateRefCount[buffer - 1]--;
}
else
{ {
SpinAcquire(BufMgrLock); SpinAcquire(BufMgrLock);
PrivateRefCount[buffer - 1] = 0;
Assert(bufHdr->refcount > 0); Assert(bufHdr->refcount > 0);
bufHdr->refcount--; bufHdr->refcount--;
if (bufHdr->refcount == 0) if (bufHdr->refcount == 0)
...@@ -1185,10 +1190,7 @@ recheck: ...@@ -1185,10 +1190,7 @@ recheck:
/* Assert checks that buffer will actually get freed! */ /* Assert checks that buffer will actually get freed! */
Assert(PrivateRefCount[i - 1] == 1 && Assert(PrivateRefCount[i - 1] == 1 &&
bufHdr->refcount == 1); bufHdr->refcount == 1);
/* ReleaseBuffer expects we do not hold the lock at entry */ ReleaseBufferWithBufferLock(i);
SpinRelease(BufMgrLock);
ReleaseBuffer(i);
SpinAcquire(BufMgrLock);
} }
/* /*
* And mark the buffer as no longer occupied by this rel. * And mark the buffer as no longer occupied by this rel.
...@@ -1270,10 +1272,7 @@ recheck: ...@@ -1270,10 +1272,7 @@ recheck:
/* Assert checks that buffer will actually get freed! */ /* Assert checks that buffer will actually get freed! */
Assert(PrivateRefCount[i - 1] == 1 && Assert(PrivateRefCount[i - 1] == 1 &&
bufHdr->refcount == 1); bufHdr->refcount == 1);
/* ReleaseBuffer expects we do not hold the lock at entry */ ReleaseBufferWithBufferLock(i);
SpinRelease(BufMgrLock);
ReleaseBuffer(i);
SpinAcquire(BufMgrLock);
} }
/* /*
* And mark the buffer as no longer occupied by this rel. * And mark the buffer as no longer occupied by this rel.
...@@ -1624,10 +1623,14 @@ ReleaseBuffer(Buffer buffer) ...@@ -1624,10 +1623,14 @@ ReleaseBuffer(Buffer buffer)
bufHdr = &BufferDescriptors[buffer - 1]; bufHdr = &BufferDescriptors[buffer - 1];
Assert(PrivateRefCount[buffer - 1] > 0); Assert(PrivateRefCount[buffer - 1] > 0);
PrivateRefCount[buffer - 1]--; if (PrivateRefCount[buffer - 1] > 1)
if (PrivateRefCount[buffer - 1] == 0) {
PrivateRefCount[buffer - 1]--;
}
else
{ {
SpinAcquire(BufMgrLock); SpinAcquire(BufMgrLock);
PrivateRefCount[buffer - 1] = 0;
Assert(bufHdr->refcount > 0); Assert(bufHdr->refcount > 0);
bufHdr->refcount--; bufHdr->refcount--;
if (bufHdr->refcount == 0) if (bufHdr->refcount == 0)
...@@ -1641,6 +1644,48 @@ ReleaseBuffer(Buffer buffer) ...@@ -1641,6 +1644,48 @@ ReleaseBuffer(Buffer buffer)
return STATUS_OK; 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 #ifdef NOT_USED
void void
IncrBufferRefCount_Debug(char *file, int line, Buffer buffer) IncrBufferRefCount_Debug(char *file, int line, Buffer buffer)
...@@ -2217,9 +2262,9 @@ MarkBufferForCleanup(Buffer buffer, void (*CleanupFunc)(Buffer)) ...@@ -2217,9 +2262,9 @@ MarkBufferForCleanup(Buffer buffer, void (*CleanupFunc)(Buffer))
SpinRelease(BufMgrLock); SpinRelease(BufMgrLock);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
PrivateRefCount[buffer - 1]--;
SpinAcquire(BufMgrLock); SpinAcquire(BufMgrLock);
PrivateRefCount[buffer - 1] = 0;
Assert(bufHdr->refcount > 0); Assert(bufHdr->refcount > 0);
bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED); bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
bufHdr->CleanupFunc = CleanupFunc; bufHdr->CleanupFunc = CleanupFunc;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -17,6 +17,7 @@
#include <sys/time.h> #include <sys/time.h>
#include <unistd.h> #include <unistd.h>
#include "miscadmin.h"
#include "storage/s_lock.h" #include "storage/s_lock.h"
...@@ -101,10 +102,16 @@ s_lock(volatile slock_t *lock, const char *file, const int line) ...@@ -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 * If you are thinking of changing this code, be careful. This same
* loop logic is used in other places that call TAS() directly. * 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)) while (TAS(lock))
{ {
s_lock_sleep(spins++, 0, lock, file, line); s_lock_sleep(spins++, 0, lock, file, line);
CHECK_FOR_INTERRUPTS();
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* *
...@@ -131,8 +131,12 @@ proc_exit(int code) ...@@ -131,8 +131,12 @@ proc_exit(int code)
* to close up shop already. Note that the signal handlers will not * to close up shop already. Note that the signal handlers will not
* set these flags again, now that proc_exit_inprogress is set. * set these flags again, now that proc_exit_inprogress is set.
*/ */
QueryCancel = false; InterruptPending = false;
ProcDiePending = false; ProcDiePending = false;
QueryCancelPending = false;
/* And let's just make *sure* we're not interrupted ... */
ImmediateInterruptOK = false;
CritSectionCount = 1;
if (DebugLvl > 1) if (DebugLvl > 1)
elog(DEBUG, "proc_exit(%d)", code); elog(DEBUG, "proc_exit(%d)", code);
...@@ -367,7 +371,7 @@ CallbackSemaphoreKill(int status, Datum semId) ...@@ -367,7 +371,7 @@ CallbackSemaphoreKill(int status, Datum semId)
/* IpcSemaphoreLock(semId, sem) - locks a semaphore */ /* IpcSemaphoreLock(semId, sem) - locks a semaphore */
/****************************************************************************/ /****************************************************************************/
void void
IpcSemaphoreLock(IpcSemaphoreId semId, int sem) IpcSemaphoreLock(IpcSemaphoreId semId, int sem, bool interruptOK)
{ {
int errStatus; int errStatus;
struct sembuf sops; struct sembuf sops;
...@@ -380,11 +384,43 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem) ...@@ -380,11 +384,43 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem)
* Note: if errStatus is -1 and errno == EINTR then it means we * Note: if errStatus is -1 and errno == EINTR then it means we
* returned from the operation prematurely because we were * returned from the operation prematurely because we were
* sent a signal. So we try and lock the semaphore again. * 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 do
{ {
ImmediateInterruptOK = interruptOK;
CHECK_FOR_INTERRUPTS();
errStatus = semop(semId, &sops, 1); errStatus = semop(semId, &sops, 1);
ImmediateInterruptOK = false;
} while (errStatus == -1 && errno == EINTR); } while (errStatus == -1 && errno == EINTR);
if (errStatus == -1) if (errStatus == -1)
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.28 2001/01/12 21:53:59 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.29 2001/01/14 05:08:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -25,9 +25,11 @@ ...@@ -25,9 +25,11 @@
#include <sys/sem.h> #include <sys/sem.h>
#endif #endif
#include "miscadmin.h"
#include "storage/proc.h" #include "storage/proc.h"
#include "storage/s_lock.h" #include "storage/s_lock.h"
/* Probably should move these to an appropriate header file */ /* Probably should move these to an appropriate header file */
extern SPINLOCK ShmemLock; extern SPINLOCK ShmemLock;
extern SPINLOCK ShmemIndexLock; extern SPINLOCK ShmemIndexLock;
...@@ -144,20 +146,21 @@ SpinAcquire(SPINLOCK lockid) ...@@ -144,20 +146,21 @@ SpinAcquire(SPINLOCK lockid)
SLock *slckP = &(SLockArray[lockid]); SLock *slckP = &(SLockArray[lockid]);
PRINT_SLDEBUG("SpinAcquire", lockid, slckP); 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 * 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)); S_LOCK(&(slckP->shlock));
PROC_INCR_SLOCK(lockid); 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); PRINT_SLDEBUG("SpinAcquire/done", lockid, slckP);
} }
...@@ -317,10 +320,16 @@ SpinFreeAllSemaphores(void) ...@@ -317,10 +320,16 @@ SpinFreeAllSemaphores(void)
void void
SpinAcquire(SPINLOCK lock) SpinAcquire(SPINLOCK lock)
{ {
/* See the TAS() version of this routine for commentary */ /*
START_CRIT_SECTION(); * See the TAS() version of this routine for primary commentary.
IpcSemaphoreLock(SpinLockIds[0], lock); *
* 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); PROC_INCR_SLOCK(lock);
START_CRIT_SECTION();
} }
/* /*
...@@ -338,8 +347,8 @@ SpinRelease(SPINLOCK lock) ...@@ -338,8 +347,8 @@ SpinRelease(SPINLOCK lock)
semval = IpcSemaphoreGetValue(SpinLockIds[0], lock); semval = IpcSemaphoreGetValue(SpinLockIds[0], lock);
Assert(semval < 1); Assert(semval < 1);
Assert(!MyProc || MyProc->sLocks[lockid] > 0);
#endif #endif
Assert(!MyProc || MyProc->sLocks[lockid] > 0);
PROC_DECR_SLOCK(lock); PROC_DECR_SLOCK(lock);
IpcSemaphoreUnlock(SpinLockIds[0], lock); IpcSemaphoreUnlock(SpinLockIds[0], lock);
END_CRIT_SECTION(); END_CRIT_SECTION();
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Outside modules can create a lock table and acquire/release * Outside modules can create a lock table and acquire/release
...@@ -726,6 +726,12 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag, ...@@ -726,6 +726,12 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
*/ */
status = WaitOnLock(lockmethod, lockmode, lock, holder); 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 * Check the holder entry status, in case something in the ipc
* communication doesn't work correctly. * communication doesn't work correctly.
...@@ -921,6 +927,8 @@ GrantLock(LOCK *lock, HOLDER *holder, LOCKMODE lockmode) ...@@ -921,6 +927,8 @@ GrantLock(LOCK *lock, HOLDER *holder, LOCKMODE lockmode)
lock->nActive++; lock->nActive++;
lock->activeHolders[lockmode]++; lock->activeHolders[lockmode]++;
lock->mask |= BITS_ON[lockmode]; lock->mask |= BITS_ON[lockmode];
if (lock->activeHolders[lockmode] == lock->holders[lockmode])
lock->waitMask &= BITS_OFF[lockmode];
LOCK_PRINT("GrantLock", lock, lockmode); LOCK_PRINT("GrantLock", lock, lockmode);
Assert((lock->nActive > 0) && (lock->activeHolders[lockmode] > 0)); Assert((lock->nActive > 0) && (lock->activeHolders[lockmode] > 0));
Assert(lock->nActive <= lock->nHolding); Assert(lock->nActive <= lock->nHolding);
...@@ -960,6 +968,17 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode, ...@@ -960,6 +968,17 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
strcat(new_status, " waiting"); strcat(new_status, " waiting");
set_ps_display(new_status); 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, if (ProcSleep(lockMethodTable->ctl,
lockmode, lockmode,
lock, lock,
...@@ -967,26 +986,16 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode, ...@@ -967,26 +986,16 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
{ {
/* ------------------- /* -------------------
* We failed as a result of a deadlock, see HandleDeadLock(). * We failed as a result of a deadlock, see HandleDeadLock().
* Decrement the lock nHolding and holders fields as * Quit now. Removal of the holder and lock objects, if no longer
* we are no longer waiting on this lock. Removal of the holder and * needed, will happen in xact cleanup (see above for motivation).
* lock objects, if no longer needed, will happen in xact cleanup.
* ------------------- * -------------------
*/ */
lock->nHolding--;
lock->holders[lockmode]--;
LOCK_PRINT("WaitOnLock: aborting on lock", lock, 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); SpinRelease(lockMethodTable->ctl->masterLock);
elog(ERROR, DeadLockMessage); elog(ERROR, DeadLockMessage);
/* not reached */ /* not reached */
} }
if (lock->activeHolders[lockmode] == lock->holders[lockmode])
lock->waitMask &= BITS_OFF[lockmode];
set_ps_display(old_status); set_ps_display(old_status);
pfree(old_status); pfree(old_status);
pfree(new_status); pfree(new_status);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -48,7 +48,7 @@
* This is so that we can support more backends. (system-wide semaphore * This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95 * 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 "postgres.h"
...@@ -78,11 +78,6 @@ ...@@ -78,11 +78,6 @@
#include "storage/proc.h" #include "storage/proc.h"
void HandleDeadLock(SIGNAL_ARGS);
static void ProcFreeAllSemaphores(void);
static bool GetOffWaitQueue(PROC *);
int DeadlockTimeout = 1000; int DeadlockTimeout = 1000;
/* -------------------- /* --------------------
...@@ -98,9 +93,14 @@ static PROC_HDR *ProcGlobal = NULL; ...@@ -98,9 +93,14 @@ static PROC_HDR *ProcGlobal = NULL;
PROC *MyProc = 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 ProcGetNewSemIdAndNum(IpcSemaphoreId *semId, int *semNum);
static void ProcFreeSem(IpcSemaphoreId semId, int semNum); static void ProcFreeSem(IpcSemaphoreId semId, int semNum);
static void ZeroProcSemaphore(PROC *proc);
static void ProcFreeAllSemaphores(void);
/* /*
* InitProcGlobal - * InitProcGlobal -
...@@ -241,27 +241,23 @@ InitProcess(void) ...@@ -241,27 +241,23 @@ InitProcess(void)
MemSet(MyProc->sLocks, 0, sizeof(MyProc->sLocks)); MemSet(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
MyProc->sLocks[ProcStructLock] = 1; MyProc->sLocks[ProcStructLock] = 1;
/*
* Set up a wait-semaphore for the proc.
*/
if (IsUnderPostmaster) if (IsUnderPostmaster)
{ {
IpcSemaphoreId semId; ProcGetNewSemIdAndNum(&MyProc->sem.semId, &MyProc->sem.semNum);
int semNum;
union semun semun;
ProcGetNewSemIdAndNum(&semId, &semNum);
/* /*
* we might be reusing a semaphore that belongs to a dead backend. * we might be reusing a semaphore that belongs to a dead backend.
* So be careful and reinitialize its value here. * So be careful and reinitialize its value here.
*/ */
semun.val = 1; ZeroProcSemaphore(MyProc);
semctl(semId, semNum, SETVAL, semun);
IpcSemaphoreLock(semId, semNum);
MyProc->sem.semId = semId;
MyProc->sem.semNum = semNum;
} }
else else
{
MyProc->sem.semId = -1; MyProc->sem.semId = -1;
MyProc->sem.semNum = -1;
}
MyProc->pid = MyProcPid; MyProc->pid = MyProcPid;
MyProc->databaseId = MyDatabaseId; MyProc->databaseId = MyDatabaseId;
...@@ -282,67 +278,126 @@ InitProcess(void) ...@@ -282,67 +278,126 @@ InitProcess(void)
* ------------------------- * -------------------------
*/ */
location = MAKE_OFFSET(MyProc); 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"); elog(STOP, "InitProcess: ShmemPID table broken");
MyProc->errType = NO_ERROR; MyProc->errType = NO_ERROR;
SHMQueueElemInit(&(MyProc->links)); 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, * 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 * even though their holder counts might now have gone to zero. That will
* happen during a subsequent LockReleaseAll call, which we expect will happen * happen during a subsequent LockReleaseAll call, which we expect will happen
* during transaction cleanup. (Removal of a proc from its wait queue by * during transaction cleanup. (Removal of a proc from its wait queue by
* this routine can only happen if we are aborting the transaction.) * this routine can only happen if we are aborting the transaction.)
* -----------------------
*/ */
static bool static void
GetOffWaitQueue(PROC *proc) RemoveFromWaitQueue(PROC *proc)
{ {
bool gotoff = false; LOCK *waitLock = proc->waitLock;
LOCKMODE lockmode = proc->waitLockMode;
LockLockTable(); /* Make sure proc is waiting */
if (proc->links.next != INVALID_OFFSET) 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; struct itimerval timeval,
LOCKMODE lockmode = proc->waitLockMode; dummy;
/* Remove proc from lock's wait queue */ MemSet(&timeval, 0, sizeof(struct itimerval));
Assert(waitLock); setitimer(ITIMER_REAL, &timeval, &dummy);
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;
} }
#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(); 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 * ProcReleaseLocks() -- release locks associated with current transaction
* at transaction commit or abort * at transaction commit or abort
...@@ -360,15 +415,17 @@ ProcReleaseLocks(bool isCommit) ...@@ -360,15 +415,17 @@ ProcReleaseLocks(bool isCommit)
{ {
if (!MyProc) if (!MyProc)
return; return;
GetOffWaitQueue(MyProc); /* If waiting, get off wait queue (should only be needed after error) */
LockWaitCancel();
/* Release locks */
LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc, LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc,
!isCommit, GetCurrentTransactionId()); !isCommit, GetCurrentTransactionId());
} }
/* /*
* ProcRemove - * ProcRemove -
* used by the postmaster to clean up the global tables. This also frees * called by the postmaster to clean up the global tables after a
* up the semaphore used for the lmgr of the process. * backend exits. This also frees up the proc's wait semaphore.
*/ */
bool bool
ProcRemove(int pid) ProcRemove(int pid)
...@@ -376,8 +433,6 @@ ProcRemove(int pid) ...@@ -376,8 +433,6 @@ ProcRemove(int pid)
SHMEM_OFFSET location; SHMEM_OFFSET location;
PROC *proc; PROC *proc;
location = INVALID_OFFSET;
location = ShmemPIDDestroy(pid); location = ShmemPIDDestroy(pid);
if (location == INVALID_OFFSET) if (location == INVALID_OFFSET)
return FALSE; return FALSE;
...@@ -398,43 +453,30 @@ ProcRemove(int pid) ...@@ -398,43 +453,30 @@ ProcRemove(int pid)
/* /*
* ProcKill() -- Destroy the per-proc data structure for * ProcKill() -- Destroy the per-proc data structure for
* this process. Release any of its held spin locks. * 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 static void
ProcKill(int exitStatus, Datum pid) ProcKill(void)
{ {
PROC *proc; Assert(MyProc);
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);
/* Release any spinlocks the proc is holding */ /* Release any spinlocks I am holding */
ProcReleaseSpins(proc); ProcReleaseSpins(MyProc);
/* Get the proc off any wait queue it might be on */ /* Get off any wait queue I might be on */
GetOffWaitQueue(proc); LockWaitCancel();
/* Remove from the standard lock table */ /* Remove from the standard lock table */
LockReleaseAll(DEFAULT_LOCKMETHOD, proc, true, InvalidTransactionId); LockReleaseAll(DEFAULT_LOCKMETHOD, MyProc, true, InvalidTransactionId);
#ifdef USER_LOCKS #ifdef USER_LOCKS
/* Remove from the user lock table */ /* Remove from the user lock table */
LockReleaseAll(USER_LOCKMETHOD, proc, true, InvalidTransactionId); LockReleaseAll(USER_LOCKMETHOD, MyProc, true, InvalidTransactionId);
#endif #endif
MyProc = NULL;
} }
/* /*
...@@ -476,69 +518,14 @@ ProcQueueInit(PROC_QUEUE *queue) ...@@ -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 * ProcSleep -- put a process to sleep
* *
* P() on the semaphore should put us to sleep. The process * P() on the semaphore should put us to sleep. The process
* semaphore is cleared by default, so the first time we try * semaphore is normally zero, so when we try to acquire it, we sleep.
* 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). * Result is NO_ERROR if we acquired the lock, STATUS_ERROR if not (deadlock).
* *
...@@ -629,7 +616,7 @@ ProcSleep(LOCKMETHODCTL *lockctl, ...@@ -629,7 +616,7 @@ ProcSleep(LOCKMETHODCTL *lockctl,
ins:; ins:;
/* ------------------- /* -------------------
* assume that these two operations are atomic (because * Insert self into queue. These operations are atomic (because
* of the spinlock). * of the spinlock).
* ------------------- * -------------------
*/ */
...@@ -640,6 +627,18 @@ ins:; ...@@ -640,6 +627,18 @@ ins:;
MyProc->errType = NO_ERROR; /* initialize result for success */ 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); SpinRelease(spinlock);
/* -------------- /* --------------
...@@ -667,8 +666,6 @@ ins:; ...@@ -667,8 +666,6 @@ ins:;
elog(FATAL, "ProcSleep: Unable to set timer for process wakeup"); elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
#endif #endif
SetWaitingForLock(true);
/* -------------- /* --------------
* If someone wakes us between SpinRelease and IpcSemaphoreLock, * If someone wakes us between SpinRelease and IpcSemaphoreLock,
* IpcSemaphoreLock will not block. The wakeup is "saved" by * IpcSemaphoreLock will not block. The wakeup is "saved" by
...@@ -676,19 +673,22 @@ ins:; ...@@ -676,19 +673,22 @@ ins:;
* is invoked but does not detect a deadlock, IpcSemaphoreLock() * is invoked but does not detect a deadlock, IpcSemaphoreLock()
* will continue to wait. There used to be a loop here, but it * will continue to wait. There used to be a loop here, but it
* was useless code... * 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); IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, true);
lockWaiting = false;
/* --------------- /* ---------------
* Disable the timer, if it's still running * Disable the timer, if it's still running
* --------------- * ---------------
*/ */
#ifndef __BEOS__ #ifndef __BEOS__
timeval.it_value.tv_sec = 0; MemSet(&timeval, 0, sizeof(struct itimerval));
timeval.it_value.tv_usec = 0;
if (setitimer(ITIMER_REAL, &timeval, &dummy)) if (setitimer(ITIMER_REAL, &timeval, &dummy))
elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup"); elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
#else #else
...@@ -696,9 +696,16 @@ ins:; ...@@ -696,9 +696,16 @@ ins:;
elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup"); elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
#endif #endif
/*
* Now there is nothing for LockWaitCancel to do.
*/
waitingForLock = false;
/* ---------------- /* ----------------
* We were assumed to be in a critical section when we went * Re-acquire the locktable's spin lock.
* to sleep. *
* 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); SpinAcquire(spinlock);
...@@ -836,20 +843,24 @@ ProcAddLock(SHM_QUEUE *elem) ...@@ -836,20 +843,24 @@ ProcAddLock(SHM_QUEUE *elem)
/* -------------------- /* --------------------
* We only get to this routine if we got SIGALRM after DeadlockTimeout * 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 * while waiting for a lock to be released by some other process. Look
* a real deadlock, we must also indicate that I'm no longer waiting * to see if there's a deadlock; if not, just return and continue waiting.
* on a lock so that other processes don't try to wake me up and screw * If we have a real deadlock, remove ourselves from the lock's wait queue
* up my semaphore. * and signal an error to ProcSleep.
* -------------------- * --------------------
*/ */
void void
HandleDeadLock(SIGNAL_ARGS) HandleDeadLock(SIGNAL_ARGS)
{ {
int save_errno = errno; 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(); LockLockTable();
/* --------------------- /* ---------------------
...@@ -869,7 +880,6 @@ HandleDeadLock(SIGNAL_ARGS) ...@@ -869,7 +880,6 @@ HandleDeadLock(SIGNAL_ARGS)
{ {
UnlockLockTable(); UnlockLockTable();
errno = save_errno; errno = save_errno;
SetWaitingForLock(isWaitingForLock); /* restore waiting status */
return; return;
} }
...@@ -883,22 +893,23 @@ HandleDeadLock(SIGNAL_ARGS) ...@@ -883,22 +893,23 @@ HandleDeadLock(SIGNAL_ARGS)
/* No deadlock, so keep waiting */ /* No deadlock, so keep waiting */
UnlockLockTable(); UnlockLockTable();
errno = save_errno; errno = save_errno;
SetWaitingForLock(isWaitingForLock); /* restore waiting status */
return; 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; RemoveFromWaitQueue(MyProc);
Assert(mywaitlock->waitProcs.size > 0);
--mywaitlock->waitProcs.size; /* -------------
SHMQueueDelete(&(MyProc->links)); * Set MyProc->errType to STATUS_ERROR so that ProcSleep will
SHMQueueElemInit(&(MyProc->links)); * report an error after we return from this signal handler.
MyProc->waitLock = NULL; * -------------
MyProc->waitHolder = NULL; */
isWaitingForLock = false; /* wait for lock no longer */ MyProc->errType = STATUS_ERROR;
/* ------------------ /* ------------------
* Unlock my semaphore so that the interrupted ProcSleep() call can finish. * Unlock my semaphore so that the interrupted ProcSleep() call can finish.
...@@ -906,17 +917,16 @@ HandleDeadLock(SIGNAL_ARGS) ...@@ -906,17 +917,16 @@ HandleDeadLock(SIGNAL_ARGS)
*/ */
IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum); IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum);
/* ------------- /* ------------------
* Set MyProc->errType to STATUS_ERROR so that we abort after * We're done here. Transaction abort caused by the error that ProcSleep
* returning from this handler. * 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
MyProc->errType = STATUS_ERROR; * 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
* if this doesn't follow the IpcSemaphoreUnlock then we get lock * waking up any such processes.
* table corruption ("LockReplace: xid table corrupted") due to race * ------------------
* conditions. i don't claim to understand this...
*/ */
UnlockLockTable(); UnlockLockTable();
errno = save_errno; errno = save_errno;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -84,9 +84,6 @@ bool Log_connections = false; ...@@ -84,9 +84,6 @@ bool Log_connections = false;
CommandDest whereToSendOutput = Debug; CommandDest whereToSendOutput = Debug;
extern void HandleDeadLock(SIGNAL_ARGS);
static bool dontExecute = false; static bool dontExecute = false;
/* note: these declarations had better match tcopprot.h */ /* note: these declarations had better match tcopprot.h */
...@@ -94,7 +91,6 @@ DLLIMPORT sigjmp_buf Warn_restart; ...@@ -94,7 +91,6 @@ DLLIMPORT sigjmp_buf Warn_restart;
bool Warn_restart_ready = false; bool Warn_restart_ready = false;
bool InError = false; bool InError = false;
volatile bool ProcDiePending = false;
static bool EchoQuery = false; /* default don't echo */ static bool EchoQuery = false; /* default don't echo */
char pg_pathname[MAXPGPATH]; char pg_pathname[MAXPGPATH];
...@@ -732,8 +728,7 @@ pg_exec_query_string(char *query_string, /* string to execute */ ...@@ -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 we got a cancel signal in parsing or prior command, quit */
if (QueryCancel) CHECK_FOR_INTERRUPTS();
CancelQuery();
/* /*
* OK to analyze and rewrite this query. * OK to analyze and rewrite this query.
...@@ -766,8 +761,7 @@ pg_exec_query_string(char *query_string, /* string to execute */ ...@@ -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 we got a cancel signal in analysis or prior command, quit */
if (QueryCancel) CHECK_FOR_INTERRUPTS();
CancelQuery();
if (querytree->commandType == CMD_UTILITY) if (querytree->commandType == CMD_UTILITY)
{ {
...@@ -793,8 +787,7 @@ pg_exec_query_string(char *query_string, /* string to execute */ ...@@ -793,8 +787,7 @@ pg_exec_query_string(char *query_string, /* string to execute */
plan = pg_plan_query(querytree); plan = pg_plan_query(querytree);
/* if we got a cancel signal whilst planning, quit */ /* if we got a cancel signal whilst planning, quit */
if (QueryCancel) CHECK_FOR_INTERRUPTS();
CancelQuery();
/* Initialize snapshot state for query */ /* Initialize snapshot state for query */
SetQuerySnapshot(); SetQuerySnapshot();
...@@ -898,40 +891,15 @@ finish_xact_command(void) ...@@ -898,40 +891,15 @@ finish_xact_command(void)
/* -------------------------------- /* --------------------------------
* signal handler routines used in PostgresMain() * 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) * quickdie() occurs when signalled SIGUSR1 by the postmaster.
{ *
/* Don't joggle the elbow of proc_exit */ * Some backend has bought the farm,
if (proc_exit_inprogress) * so we need to stop what we're doing and exit.
return; */
/* Don't joggle the elbow of a critical section, either */
if (CritSectionCount > 0)
{
QueryCancel = true;
return;
}
siglongjmp(Warn_restart, 1);
}
static void static void
quickdie(SIGNAL_ARGS) quickdie(SIGNAL_ARGS)
{ {
...@@ -943,88 +911,69 @@ quickdie(SIGNAL_ARGS) ...@@ -943,88 +911,69 @@ quickdie(SIGNAL_ARGS)
" going to terminate your database system connection and exit." " going to terminate your database system connection and exit."
"\n\tPlease reconnect to the database system and repeat your query."); "\n\tPlease reconnect to the database system and repeat your query.");
/* /*
* DO NOT proc_exit(0) -- we're here because shared memory may be * DO NOT proc_exit() -- we're here because shared memory may be
* corrupted, so we don't want to flush any shared state to stable * corrupted, so we don't want to try to clean up our transaction.
* storage. Just nail the windows shut and get out of town. * 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); exit(1);
} }
/* /*
* Abort transaction and exit * Shutdown signal from postmaster: abort transaction and exit
* at soonest convenient time
*/ */
void void
die(SIGNAL_ARGS) die(SIGNAL_ARGS)
{ {
int save_errno = errno; int save_errno = errno;
PG_SETMASK(&BlockSig);
/* Don't joggle the elbow of proc_exit */ /* Don't joggle the elbow of proc_exit */
if (proc_exit_inprogress) if (! proc_exit_inprogress)
{
errno = save_errno;
return;
}
/* Don't joggle the elbow of a critical section, either */
if (CritSectionCount > 0)
{ {
InterruptPending = true;
ProcDiePending = 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 * Query-cancel signal from postmaster: abort current transaction
* END_CRIT_SECTION(). * 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 static void
QueryCancelHandler(SIGNAL_ARGS) QueryCancelHandler(SIGNAL_ARGS)
{ {
int save_errno = errno; int save_errno = errno;
/* Don't joggle the elbow of proc_exit, nor an already-in-progress abort */ /* 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; InterruptPending = true;
return; 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; 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 */ /* signal handler for floating point exception */
static void static void
FloatExceptionHandler(SIGNAL_ARGS) FloatExceptionHandler(SIGNAL_ARGS)
...@@ -1034,6 +983,7 @@ FloatExceptionHandler(SIGNAL_ARGS) ...@@ -1034,6 +983,7 @@ FloatExceptionHandler(SIGNAL_ARGS)
" or was a divide by zero"); " or was a divide by zero");
} }
/* SIGHUP: set flag to re-read config file at next convenient time */
static void static void
SigHupHandler(SIGNAL_ARGS) SigHupHandler(SIGNAL_ARGS)
{ {
...@@ -1041,6 +991,36 @@ 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 static void
usage(char *progname) usage(char *progname)
...@@ -1502,9 +1482,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -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(SIGHUP, SigHupHandler); /* set flag to read config file */
pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */ pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */
pqsignal(SIGQUIT, handle_warn); /* handle error */ pqsignal(SIGTERM, die); /* cancel current query and exit */
pqsignal(SIGTERM, die); pqsignal(SIGQUIT, die); /* could reassign this sig for another use */
pqsignal(SIGALRM, HandleDeadLock); pqsignal(SIGALRM, HandleDeadLock);
/* /*
...@@ -1517,10 +1497,15 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1517,10 +1497,15 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
pqsignal(SIGUSR1, quickdie); pqsignal(SIGUSR1, quickdie);
pqsignal(SIGUSR2, Async_NotifyHandler); /* flush also sinval cache */ pqsignal(SIGUSR2, Async_NotifyHandler); /* flush also sinval cache */
pqsignal(SIGFPE, FloatExceptionHandler); 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(SIGTTIN, SIG_DFL);
pqsignal(SIGTTOU, SIG_DFL); pqsignal(SIGTTOU, SIG_DFL);
pqsignal(SIGCONT, SIG_DFL); pqsignal(SIGCONT, SIG_DFL);
pqsignal(SIGWINCH, SIG_DFL);
pqinitmask(); pqinitmask();
...@@ -1683,7 +1668,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1683,7 +1668,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
puts("\nPOSTGRES backend interactive interface "); 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 ...@@ -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() * consider the probability that it should be in AbortTransaction()
* instead. * 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. * Make sure we are in a valid memory context during recovery.
* *
* We use ErrorContext in hopes that it will have some free space * 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 ...@@ -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().) * successfully. (Flag was set in elog.c before longjmp().)
*/ */
InError = false; 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) */ 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 ...@@ -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, * (2) deal with pending asynchronous NOTIFY from other backends,
* and enable async.c's signal handler to execute NOTIFY directly. * 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 */ QueryCancelPending = false; /* forget any earlier CANCEL signal */
SetWaitingForLock(false);
EnableNotifyInterrupt(); 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) * (3) read a command (loop blocks here)
* ---------------- * ----------------
*/ */
set_ps_display("idle");
firstchar = ReadCommand(parser_input); 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(); DisableNotifyInterrupt();
/* ---------------- /* ----------------
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...) ...@@ -120,8 +120,10 @@ elog(int lev, const char *fmt, ...)
char *msg_buf = msg_fixedbuf; char *msg_buf = msg_fixedbuf;
/* this buffer is only used for strange values of lev: */ /* this buffer is only used for strange values of lev: */
char prefix_buf[32]; char prefix_buf[32];
#ifdef HAVE_SYS_NERR
/* this buffer is only used if errno has a bogus value: */ /* this buffer is only used if errno has a bogus value: */
char errorstr_buf[32]; char errorstr_buf[32];
#endif
const char *errorstr; const char *errorstr;
const char *prefix; const char *prefix;
const char *cp; const char *cp;
...@@ -145,17 +147,16 @@ elog(int lev, const char *fmt, ...) ...@@ -145,17 +147,16 @@ elog(int lev, const char *fmt, ...)
errorstr = errorstr_buf; errorstr = errorstr_buf;
} }
#else #else
/* assume strerror() will cope gracefully with bogus errno values */
errorstr = strerror(errno); errorstr = strerror(errno);
#endif #endif
if (lev == ERROR || lev == FATAL) /* Convert initialization errors into fatal errors.
{ * This is probably redundant, because Warn_restart_ready won't
/* this is probably redundant... */ * be set anyway...
if (IsInitProcessingMode()) */
lev = FATAL; if (lev == ERROR && IsInitProcessingMode())
if (CritSectionCount > 0) lev = FATAL;
lev = STOP;
}
/* choose message prefix and indent level */ /* choose message prefix and indent level */
switch (lev) switch (lev)
...@@ -366,8 +367,6 @@ elog(int lev, const char *fmt, ...) ...@@ -366,8 +367,6 @@ elog(int lev, const char *fmt, ...)
if (Debugfile >= 0 && Use_syslog <= 1) if (Debugfile >= 0 && Use_syslog <= 1)
write(Debugfile, msg_buf, len); write(Debugfile, msg_buf, len);
#ifndef PG_STANDALONE
if (lev > DEBUG && whereToSendOutput == Remote) if (lev > DEBUG && whereToSendOutput == Remote)
{ {
/* Send IPC message to the front-end program */ /* Send IPC message to the front-end program */
...@@ -424,8 +423,6 @@ elog(int lev, const char *fmt, ...) ...@@ -424,8 +423,6 @@ elog(int lev, const char *fmt, ...)
fputs(msg_buf, stderr); fputs(msg_buf, stderr);
} }
#endif /* !PG_STANDALONE */
/* done with the message, release space */ /* done with the message, release space */
if (fmt_buf != fmt_fixedbuf) if (fmt_buf != fmt_fixedbuf)
free(fmt_buf); free(fmt_buf);
...@@ -437,6 +434,8 @@ elog(int lev, const char *fmt, ...) ...@@ -437,6 +434,8 @@ elog(int lev, const char *fmt, ...)
*/ */
if (lev == ERROR || lev == FATAL) 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. * For a FATAL error, we let proc_exit clean up and exit.
...@@ -477,7 +476,6 @@ elog(int lev, const char *fmt, ...) ...@@ -477,7 +476,6 @@ elog(int lev, const char *fmt, ...)
if (lev > FATAL) if (lev > FATAL)
{ {
/* /*
* Serious crash time. Postmaster will observe nonzero process * Serious crash time. Postmaster will observe nonzero process
* exit status and kill the other backends too. * exit status and kill the other backends too.
...@@ -485,6 +483,7 @@ elog(int lev, const char *fmt, ...) ...@@ -485,6 +483,7 @@ elog(int lev, const char *fmt, ...)
* XXX: what if we are *in* the postmaster? proc_exit() won't kill * XXX: what if we are *in* the postmaster? proc_exit() won't kill
* our children... * our children...
*/ */
ImmediateInterruptOK = false;
fflush(stdout); fflush(stdout);
fflush(stderr); fflush(stderr);
proc_exit(lev); proc_exit(lev);
...@@ -493,8 +492,6 @@ elog(int lev, const char *fmt, ...) ...@@ -493,8 +492,6 @@ elog(int lev, const char *fmt, ...)
/* We reach here if lev <= NOTICE. OK to return to caller. */ /* We reach here if lev <= NOTICE. OK to return to caller. */
} }
#ifndef PG_STANDALONE
int int
DebugFileOpen(void) DebugFileOpen(void)
{ {
...@@ -556,9 +553,6 @@ DebugFileOpen(void) ...@@ -556,9 +553,6 @@ DebugFileOpen(void)
return Debugfile; return Debugfile;
} }
#endif
/* /*
* Return a timestamp string like * Return a timestamp string like
...@@ -602,6 +596,10 @@ print_pid(void) ...@@ -602,6 +596,10 @@ print_pid(void)
#ifdef ENABLE_SYSLOG #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. * Write a message line to syslog if the syslog option is set.
* *
...@@ -613,10 +611,6 @@ print_pid(void) ...@@ -613,10 +611,6 @@ print_pid(void)
static void static void
write_syslog(int level, const char *line) write_syslog(int level, const char *line)
{ {
#ifndef PG_SYSLOG_LIMIT
# define PG_SYSLOG_LIMIT 128
#endif
static bool openlog_done = false; static bool openlog_done = false;
static unsigned long seq = 0; static unsigned long seq = 0;
static int syslog_fac = LOG_LOCAL0; static int syslog_fac = LOG_LOCAL0;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Globals used all over the place should be declared here and not * Globals used all over the place should be declared here and not
...@@ -34,7 +34,12 @@ ProtocolVersion FrontendProtocol = PG_PROTOCOL_LATEST; ...@@ -34,7 +34,12 @@ ProtocolVersion FrontendProtocol = PG_PROTOCOL_LATEST;
bool Noversion = false; bool Noversion = false;
bool Quiet = 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; int MyProcPid;
struct Port *MyProcPort; struct Port *MyProcPort;
...@@ -56,9 +61,7 @@ BackendId MyBackendId; ...@@ -56,9 +61,7 @@ BackendId MyBackendId;
char *DatabaseName = NULL; char *DatabaseName = NULL;
char *DatabasePath = NULL; char *DatabasePath = NULL;
bool MyDatabaseIdIsInitialized = false;
Oid MyDatabaseId = InvalidOid; Oid MyDatabaseId = InvalidOid;
bool TransactionInitWasProcessed = false;
bool IsUnderPostmaster = false; bool IsUnderPostmaster = false;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* PostgreSQL transaction log manager * 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 #ifndef XLOG_H
#define XLOG_H #define XLOG_H
...@@ -101,7 +101,6 @@ typedef XLogPageHeaderData *XLogPageHeader; ...@@ -101,7 +101,6 @@ typedef XLogPageHeaderData *XLogPageHeader;
extern StartUpID ThisStartUpID; /* current SUI */ extern StartUpID ThisStartUpID; /* current SUI */
extern bool InRecovery; extern bool InRecovery;
extern XLogRecPtr MyLastRecPtr; extern XLogRecPtr MyLastRecPtr;
extern volatile uint32 CritSectionCount;
typedef struct RmgrData typedef struct RmgrData
{ {
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * 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. * other files.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -23,11 +23,63 @@ ...@@ -23,11 +23,63 @@
#ifndef MISCADMIN_H #ifndef MISCADMIN_H
#define MISCADMIN_H #define MISCADMIN_H
#include <sys/types.h> /* For pid_t */
#include "postgres.h"
#include "storage/ipc.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 -- * * globals.h -- *
*****************************************************************************/ *****************************************************************************/
...@@ -42,7 +94,6 @@ extern int PostmasterMain(int argc, char *argv[]); ...@@ -42,7 +94,6 @@ extern int PostmasterMain(int argc, char *argv[]);
*/ */
extern bool Noversion; extern bool Noversion;
extern bool Quiet; extern bool Quiet;
extern volatile bool QueryCancel;
extern char *DataDir; extern char *DataDir;
extern int MyProcPid; extern int MyProcPid;
...@@ -56,9 +107,7 @@ extern char OutputFileName[]; ...@@ -56,9 +107,7 @@ extern char OutputFileName[];
* *
* extern BackendId MyBackendId; * extern BackendId MyBackendId;
*/ */
extern bool MyDatabaseIdIsInitialized;
extern Oid MyDatabaseId; extern Oid MyDatabaseId;
extern bool TransactionInitWasProcessed;
extern bool IsUnderPostmaster; extern bool IsUnderPostmaster;
...@@ -143,7 +192,8 @@ extern void SetSessionUserIdFromUserName(const char *username); ...@@ -143,7 +192,8 @@ extern void SetSessionUserIdFromUserName(const char *username);
extern void SetDataDir(const char *dir); 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); extern int CheckPathAccess(char *path, char *name, int open_mode);
#ifdef CYR_RECODE #ifdef CYR_RECODE
...@@ -157,17 +207,17 @@ extern char *convertstr(unsigned char *buff, int len, int dest); ...@@ -157,17 +207,17 @@ extern char *convertstr(unsigned char *buff, int len, int dest);
/* /*
* Description: * Description:
* There are three processing modes in POSTGRES. They are * There are three processing modes in POSTGRES. They are
* "BootstrapProcessing or "bootstrap," InitProcessing or * BootstrapProcessing or "bootstrap," InitProcessing or
* "initialization," and NormalProcessing or "normal." * "initialization," and NormalProcessing or "normal."
* *
* The first two processing modes are used during special times. When the * The first two processing modes are used during special times. When the
* system state indicates bootstrap processing, transactions are all given * 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. * is used during the initial generation of template databases.
* *
* Initialization mode until all normal initialization is complete. * Initialization mode: used while starting a backend, until all normal
* Some code behaves differently when executed in this mode to enable * initialization is complete. Some code behaves differently when executed
* system bootstrapping. * in this mode to enable system bootstrapping.
* *
* If a POSTGRES binary is in normal mode, then all code may be executed * If a POSTGRES binary is in normal mode, then all code may be executed
* normally. * normally.
...@@ -185,27 +235,13 @@ typedef enum ProcessingMode ...@@ -185,27 +235,13 @@ typedef enum ProcessingMode
* pinit.h -- * * pinit.h -- *
* POSTGRES initialization and cleanup definitions. * * 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 */ /* in utils/init/postinit.c */
extern int lockingOff; extern int lockingOff;
extern void InitPostgres(const char *dbname, const char *username); extern void InitPostgres(const char *dbname, const char *username);
extern void BaseInit(void); extern void BaseInit(void);
/* one of the ways to get out of here */
#define ExitPostgres(status) proc_exec(status)
/* processing mode support stuff */ /* processing mode support stuff */
extern ProcessingMode Mode; extern ProcessingMode Mode;
...@@ -215,21 +251,22 @@ extern ProcessingMode Mode; ...@@ -215,21 +251,22 @@ extern ProcessingMode Mode;
#define SetProcessingMode(mode) \ #define SetProcessingMode(mode) \
do { \ do { \
AssertArg(mode == BootstrapProcessing || mode == InitProcessing || \ AssertArg((mode) == BootstrapProcessing || \
mode == NormalProcessing); \ (mode) == InitProcessing || \
Mode = mode; \ (mode) == NormalProcessing); \
Mode = (mode); \
} while(0) } while(0)
#define GetProcessingMode() Mode #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 CreateDataDirLockFile(const char *datadir, bool amPostmaster);
extern bool CreateSocketLockFile(const char *socketfile, bool amPostmaster); extern bool CreateSocketLockFile(const char *socketfile, bool amPostmaster);
extern void ValidatePgVersion(const char *path); 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 */ #endif /* MISCADMIN_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * 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 * instead include this file because on Ultrix, sys/ipc.h is not designed
...@@ -99,7 +99,7 @@ extern IpcSemaphoreId IpcSemaphoreCreate(int numSems, int permission, ...@@ -99,7 +99,7 @@ extern IpcSemaphoreId IpcSemaphoreCreate(int numSems, int permission,
int semStartValue, int semStartValue,
bool removeOnExit); bool removeOnExit);
extern void IpcSemaphoreKill(IpcSemaphoreId semId); 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 void IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem);
extern bool IpcSemaphoreTryLock(IpcSemaphoreId semId, int sem); extern bool IpcSemaphoreTryLock(IpcSemaphoreId semId, int sem);
extern int IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem); extern int IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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; ...@@ -22,9 +22,8 @@ extern int DeadlockTimeout;
typedef struct typedef struct
{ {
int sleeplock; IpcSemaphoreId semId; /* SysV semaphore set ID */
IpcSemaphoreId semId; int semNum; /* semaphore number within set */
int semNum;
} SEMA; } SEMA;
/* /*
...@@ -38,12 +37,6 @@ struct proc ...@@ -38,12 +37,6 @@ struct proc
SEMA sem; /* ONE semaphore to sleep on */ SEMA sem; /* ONE semaphore to sleep on */
int errType; /* error code tells why we woke up */ 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 TransactionId xid; /* transaction currently being executed by
* this proc */ * this proc */
...@@ -72,6 +65,9 @@ struct proc ...@@ -72,6 +65,9 @@ struct proc
extern PROC *MyProc; extern PROC *MyProc;
extern SPINLOCK ProcStructLock;
#define PROC_INCR_SLOCK(lock) \ #define PROC_INCR_SLOCK(lock) \
do { \ do { \
if (MyProc) (MyProc->sLocks[(lock)])++; \ if (MyProc) (MyProc->sLocks[(lock)])++; \
...@@ -89,11 +85,6 @@ do { \ ...@@ -89,11 +85,6 @@ do { \
#define ERR_TIMEOUT 1 #define ERR_TIMEOUT 1
#define ERR_BUFFER_IO 2 #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. * There is one ProcGlobal struct for the whole installation.
...@@ -142,5 +133,6 @@ extern int ProcLockWakeup(LOCKMETHOD lockmethod, LOCK *lock); ...@@ -142,5 +133,6 @@ extern int ProcLockWakeup(LOCKMETHOD lockmethod, LOCK *lock);
extern void ProcAddLock(SHM_QUEUE *elem); extern void ProcAddLock(SHM_QUEUE *elem);
extern void ProcReleaseSpins(PROC *proc); extern void ProcReleaseSpins(PROC *proc);
extern void LockWaitCancel(void); extern void LockWaitCancel(void);
extern void HandleDeadLock(SIGNAL_ARGS);
#endif /* PROC_H */ #endif /* PROC_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * OLD COMMENTS
* This file was created so that other c files could get the two * 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, ...@@ -40,9 +40,7 @@ extern void pg_exec_query_string(char *query_string,
#endif /* BOOTSTRAP_INCLUDE */ #endif /* BOOTSTRAP_INCLUDE */
extern void handle_warn(SIGNAL_ARGS);
extern void die(SIGNAL_ARGS); extern void die(SIGNAL_ARGS);
extern void CancelQuery(void);
extern int PostgresMain(int argc, char *argv[], extern int PostgresMain(int argc, char *argv[],
int real_argc, char *real_argv[], const char *username); int real_argc, char *real_argv[], const char *username);
extern void ResetUsage(void); extern void ResetUsage(void);
......
...@@ -7,13 +7,14 @@ ...@@ -7,13 +7,14 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 #ifndef ELOG_H
#define ELOG_H #define ELOG_H
/* Error level codes */
#define NOTICE 0 /* random info - no special action */ #define NOTICE 0 /* random info - no special action */
#define ERROR (-1) /* user error - return to known state */ #define ERROR (-1) /* user error - return to known state */
#define FATAL 1 /* fatal error - abort process */ #define FATAL 1 /* fatal error - abort process */
...@@ -23,47 +24,25 @@ ...@@ -23,47 +24,25 @@
#define LOG DEBUG #define LOG DEBUG
#define NOIND (-3) /* debug message, don't indent as far */ #define NOIND (-3) /* debug message, don't indent as far */
/* Configurable parameters */
#ifdef ENABLE_SYSLOG #ifdef ENABLE_SYSLOG
extern int Use_syslog; extern int Use_syslog;
#endif #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_timestamp;
extern bool Log_pid; extern bool Log_pid;
#ifndef __GNUC__ #ifndef __GNUC__
extern void elog(int lev, const char *fmt,...); extern void elog(int lev, const char *fmt, ...);
#else #else
/* This extension allows gcc to check the format string for consistency with /* This extension allows gcc to check the format string for consistency with
the supplied arguments. */ 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 #endif
#ifndef PG_STANDALONE
extern int DebugFileOpen(void); extern int DebugFileOpen(void);
#endif
#endif /* ELOG_H */ #endif /* ELOG_H */
...@@ -12,10 +12,12 @@ ...@@ -12,10 +12,12 @@
* *
* *
* IDENTIFICATION * 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 <ctype.h>
#include <sys/types.h> #include <sys/types.h>
#include <limits.h> #include <limits.h>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment