mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
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.
This commit is contained in:
@ -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 @@
|
|||||||
|
|
||||||
#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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
s->state = TRANS_DEFAULT;
|
s->state = TRANS_DEFAULT;
|
||||||
|
|
||||||
|
END_CRIT_SECTION();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
@ -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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
* State remains TRANS_ABORT until CleanupTransaction().
|
* State remains TRANS_ABORT until CleanupTransaction().
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
END_CRIT_SECTION();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
|
@ -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 @@
|
|||||||
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 @@
|
|||||||
* 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[])
|
|||||||
|
|
||||||
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[])
|
|||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
|
|
||||||
while (!done)
|
while (!done)
|
||||||
{
|
{
|
||||||
if (QueryCancel)
|
CHECK_FOR_INTERRUPTS();
|
||||||
{
|
|
||||||
lineno = 0;
|
|
||||||
CancelQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
lineno++;
|
lineno++;
|
||||||
|
|
||||||
|
@ -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)
|
|||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
{
|
{
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
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,
|
|||||||
{
|
{
|
||||||
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:
|
|||||||
/* 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:
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
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))
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
#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)
|
|||||||
/*
|
/*
|
||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
* 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)
|
|||||||
/* 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)
|
|||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
{
|
{
|
||||||
/* -------------------
|
/* -------------------
|
||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
* 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 @@
|
|||||||
#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;
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
* -------------------------
|
* -------------------------
|
||||||
*/
|
*/
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
/*
|
/*
|
||||||
* 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)
|
/* Release any spinlocks I am holding */
|
||||||
{
|
ProcReleaseSpins(MyProc);
|
||||||
proc = MyProc;
|
|
||||||
MyProc = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* This path is dead code at the moment ... */
|
|
||||||
SHMEM_OFFSET location = INVALID_OFFSET;
|
|
||||||
|
|
||||||
ShmemPIDLookup((int) pid, &location);
|
/* Get off any wait queue I might be on */
|
||||||
if (location == INVALID_OFFSET)
|
LockWaitCancel();
|
||||||
return;
|
|
||||||
proc = (PROC *) MAKE_PTR(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert(proc);
|
|
||||||
|
|
||||||
/* Release any spinlocks the proc is holding */
|
|
||||||
ProcReleaseSpins(proc);
|
|
||||||
|
|
||||||
/* Get the proc off any wait queue it might be on */
|
|
||||||
GetOffWaitQueue(proc);
|
|
||||||
|
|
||||||
/* 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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,
|
|||||||
|
|
||||||
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:;
|
|||||||
|
|
||||||
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:;
|
|||||||
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:;
|
|||||||
* 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:;
|
|||||||
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)
|
|||||||
|
|
||||||
/* --------------------
|
/* --------------------
|
||||||
* 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)
|
|||||||
{
|
{
|
||||||
UnlockLockTable();
|
UnlockLockTable();
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
SetWaitingForLock(isWaitingForLock); /* restore waiting status */
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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)
|
|||||||
*/
|
*/
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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;
|
|||||||
|
|
||||||
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;
|
|||||||
|
|
||||||
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 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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 */
|
|||||||
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)
|
|||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* 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)
|
|||||||
" 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)
|
|||||||
" 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
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
|
|||||||
* 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
|
|||||||
* 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
|
|||||||
/* ----------------
|
/* ----------------
|
||||||
* (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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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, ...)
|
|||||||
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, ...)
|
|||||||
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, ...)
|
|||||||
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, ...)
|
|||||||
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, ...)
|
|||||||
*/
|
*/
|
||||||
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, ...)
|
|||||||
|
|
||||||
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, ...)
|
|||||||
* 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, ...)
|
|||||||
/* 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)
|
|||||||
return Debugfile;
|
return Debugfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return a timestamp string like
|
* Return a timestamp string like
|
||||||
@ -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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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;
|
|||||||
|
|
||||||
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;
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
* 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;
|
|||||||
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 @@
|
|||||||
* 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 @@
|
|||||||
#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[]);
|
|||||||
*/
|
*/
|
||||||
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[];
|
|||||||
*
|
*
|
||||||
* 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);
|
|||||||
|
|
||||||
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);
|
|||||||
/*
|
/*
|
||||||
* 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
|
|||||||
* 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;
|
|||||||
|
|
||||||
#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 @@
|
|||||||
* 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,
|
|||||||
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 @@
|
|||||||
* 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;
|
|||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
|
|
||||||
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 { \
|
|||||||
#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);
|
|||||||
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 @@
|
|||||||
* 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,
|
|||||||
|
|
||||||
#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 @@
|
|||||||
* 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 @@
|
|||||||
#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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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>
|
||||||
|
Reference in New Issue
Block a user