mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Provide support for multiplexing SIGUSR1 signal. The upcoming synchronous
replication patch needs a signal, but we've already used SIGUSR1 and SIGUSR2 in normal backends. This patch allows reusing SIGUSR1 for that, and for other purposes too if the need arises.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinval.c,v 1.86 2008/06/19 21:32:56 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinval.c,v 1.87 2008/12/09 14:28:20 heikki Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -26,8 +26,8 @@
|
||||
* Because backends sitting idle will not be reading sinval events, we
|
||||
* need a way to give an idle backend a swift kick in the rear and make
|
||||
* it catch up before the sinval queue overflows and forces it to go
|
||||
* through a cache reset exercise. This is done by sending SIGUSR1
|
||||
* to any backend that gets too far behind.
|
||||
* through a cache reset exercise. This is done by sending
|
||||
* PROCSIG_CATCHUP_INTERRUPT to any backend that gets too far behind.
|
||||
*
|
||||
* State for catchup events consists of two flags: one saying whether
|
||||
* the signal handler is currently allowed to call ProcessCatchupEvent
|
||||
@ -144,9 +144,9 @@ ReceiveSharedInvalidMessages(
|
||||
|
||||
|
||||
/*
|
||||
* CatchupInterruptHandler
|
||||
* HandleCatchupInterrupt
|
||||
*
|
||||
* This is the signal handler for SIGUSR1.
|
||||
* This is called when PROCSIG_CATCHUP_INTERRUPT signal is received.
|
||||
*
|
||||
* If we are idle (catchupInterruptEnabled is set), we can safely
|
||||
* invoke ProcessCatchupEvent directly. Otherwise, just set a flag
|
||||
@ -156,13 +156,11 @@ ReceiveSharedInvalidMessages(
|
||||
* since there's no longer any reason to do anything.)
|
||||
*/
|
||||
void
|
||||
CatchupInterruptHandler(SIGNAL_ARGS)
|
||||
HandleCatchupInterrupt(void)
|
||||
{
|
||||
int save_errno = errno;
|
||||
|
||||
/*
|
||||
* Note: this is a SIGNAL HANDLER. You must be very wary what you do
|
||||
* here.
|
||||
* Note: this is called by a SIGNAL HANDLER.
|
||||
* You must be very wary what you do here.
|
||||
*/
|
||||
|
||||
/* Don't joggle the elbow of proc_exit */
|
||||
@ -216,8 +214,6 @@ CatchupInterruptHandler(SIGNAL_ARGS)
|
||||
*/
|
||||
catchupInterruptOccurred = 1;
|
||||
}
|
||||
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -289,7 +285,8 @@ DisableCatchupInterrupt(void)
|
||||
/*
|
||||
* ProcessCatchupEvent
|
||||
*
|
||||
* Respond to a catchup event (SIGUSR1) from another backend.
|
||||
* Respond to a catchup event (PROCSIG_CATCHUP_INTERRUPT) from another
|
||||
* backend.
|
||||
*
|
||||
* This is called either directly from the SIGUSR1 signal handler,
|
||||
* or the next time control reaches the outer idle loop (assuming
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.74 2008/07/18 14:45:48 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.75 2008/12/09 14:28:20 heikki Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -21,6 +21,7 @@
|
||||
#include "storage/backendid.h"
|
||||
#include "storage/ipc.h"
|
||||
#include "storage/proc.h"
|
||||
#include "storage/procarray.h"
|
||||
#include "storage/shmem.h"
|
||||
#include "storage/sinvaladt.h"
|
||||
#include "storage/spin.h"
|
||||
@ -136,9 +137,9 @@
|
||||
/* Per-backend state in shared invalidation structure */
|
||||
typedef struct ProcState
|
||||
{
|
||||
/* procPid is zero in an inactive ProcState array entry. */
|
||||
pid_t procPid; /* PID of backend, for signaling */
|
||||
/* nextMsgNum is meaningless if procPid == 0 or resetState is true. */
|
||||
/* proc is NULL in an inactive ProcState array entry. */
|
||||
PGPROC *proc; /* PGPROC entry of backend, for signaling */
|
||||
/* nextMsgNum is meaningless if proc == NULL or resetState is true. */
|
||||
int nextMsgNum; /* next message number to read */
|
||||
bool resetState; /* backend needs to reset its state */
|
||||
bool signaled; /* backend has been sent catchup signal */
|
||||
@ -235,7 +236,7 @@ CreateSharedInvalidationState(void)
|
||||
/* Mark all backends inactive, and initialize nextLXID */
|
||||
for (i = 0; i < shmInvalBuffer->maxBackends; i++)
|
||||
{
|
||||
shmInvalBuffer->procState[i].procPid = 0; /* inactive */
|
||||
shmInvalBuffer->procState[i].proc = NULL; /* inactive */
|
||||
shmInvalBuffer->procState[i].nextMsgNum = 0; /* meaningless */
|
||||
shmInvalBuffer->procState[i].resetState = false;
|
||||
shmInvalBuffer->procState[i].signaled = false;
|
||||
@ -266,7 +267,7 @@ SharedInvalBackendInit(void)
|
||||
/* Look for a free entry in the procState array */
|
||||
for (index = 0; index < segP->lastBackend; index++)
|
||||
{
|
||||
if (segP->procState[index].procPid == 0) /* inactive slot? */
|
||||
if (segP->procState[index].proc == NULL) /* inactive slot? */
|
||||
{
|
||||
stateP = &segP->procState[index];
|
||||
break;
|
||||
@ -278,7 +279,7 @@ SharedInvalBackendInit(void)
|
||||
if (segP->lastBackend < segP->maxBackends)
|
||||
{
|
||||
stateP = &segP->procState[segP->lastBackend];
|
||||
Assert(stateP->procPid == 0);
|
||||
Assert(stateP->proc == NULL);
|
||||
segP->lastBackend++;
|
||||
}
|
||||
else
|
||||
@ -303,7 +304,7 @@ SharedInvalBackendInit(void)
|
||||
nextLocalTransactionId = stateP->nextLXID;
|
||||
|
||||
/* mark myself active, with all extant messages already read */
|
||||
stateP->procPid = MyProcPid;
|
||||
stateP->proc = MyProc;
|
||||
stateP->nextMsgNum = segP->maxMsgNum;
|
||||
stateP->resetState = false;
|
||||
stateP->signaled = false;
|
||||
@ -341,7 +342,7 @@ CleanupInvalidationState(int status, Datum arg)
|
||||
stateP->nextLXID = nextLocalTransactionId;
|
||||
|
||||
/* Mark myself inactive */
|
||||
stateP->procPid = 0;
|
||||
stateP->proc = NULL;
|
||||
stateP->nextMsgNum = 0;
|
||||
stateP->resetState = false;
|
||||
stateP->signaled = false;
|
||||
@ -349,7 +350,7 @@ CleanupInvalidationState(int status, Datum arg)
|
||||
/* Recompute index of last active backend */
|
||||
for (i = segP->lastBackend; i > 0; i--)
|
||||
{
|
||||
if (segP->procState[i - 1].procPid != 0)
|
||||
if (segP->procState[i - 1].proc != NULL)
|
||||
break;
|
||||
}
|
||||
segP->lastBackend = i;
|
||||
@ -374,7 +375,7 @@ BackendIdIsActive(int backendID)
|
||||
{
|
||||
ProcState *stateP = &segP->procState[backendID - 1];
|
||||
|
||||
result = (stateP->procPid != 0);
|
||||
result = (stateP->proc != NULL);
|
||||
}
|
||||
else
|
||||
result = false;
|
||||
@ -590,7 +591,7 @@ SICleanupQueue(bool callerHasWriteLock, int minFree)
|
||||
int n = stateP->nextMsgNum;
|
||||
|
||||
/* Ignore if inactive or already in reset state */
|
||||
if (stateP->procPid == 0 || stateP->resetState)
|
||||
if (stateP->proc == NULL || stateP->resetState)
|
||||
continue;
|
||||
|
||||
/*
|
||||
@ -644,18 +645,20 @@ SICleanupQueue(bool callerHasWriteLock, int minFree)
|
||||
segP->nextThreshold = (numMsgs / CLEANUP_QUANTUM + 1) * CLEANUP_QUANTUM;
|
||||
|
||||
/*
|
||||
* Lastly, signal anyone who needs a catchup interrupt. Since kill()
|
||||
* might not be fast, we don't want to hold locks while executing it.
|
||||
* Lastly, signal anyone who needs a catchup interrupt. Since
|
||||
* SendProcSignal() might not be fast, we don't want to hold locks while
|
||||
* executing it.
|
||||
*/
|
||||
if (needSig)
|
||||
{
|
||||
pid_t his_pid = needSig->procPid;
|
||||
PGPROC *his_proc = needSig->proc;
|
||||
|
||||
needSig->signaled = true;
|
||||
LWLockRelease(SInvalReadLock);
|
||||
LWLockRelease(SInvalWriteLock);
|
||||
elog(DEBUG4, "sending sinval catchup signal to PID %d", (int) his_pid);
|
||||
kill(his_pid, SIGUSR1);
|
||||
elog(DEBUG4, "sending sinval catchup signal to PID %d",
|
||||
(int) his_proc->pid);
|
||||
SendProcSignal(his_proc, PROCSIG_CATCHUP_INTERRUPT);
|
||||
if (callerHasWriteLock)
|
||||
LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.202 2008/11/02 21:24:52 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.203 2008/12/09 14:28:20 heikki Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -289,6 +289,7 @@ InitProcess(void)
|
||||
MyProc->databaseId = InvalidOid;
|
||||
MyProc->roleId = InvalidOid;
|
||||
MyProc->inCommit = false;
|
||||
MemSet(MyProc->signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t));
|
||||
MyProc->vacuumFlags = 0;
|
||||
if (IsAutoVacuumWorkerProcess())
|
||||
MyProc->vacuumFlags |= PROC_IS_AUTOVACUUM;
|
||||
@ -428,6 +429,7 @@ InitAuxiliaryProcess(void)
|
||||
MyProc->databaseId = InvalidOid;
|
||||
MyProc->roleId = InvalidOid;
|
||||
MyProc->inCommit = false;
|
||||
MemSet(MyProc->signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t));
|
||||
/* we don't set the "is autovacuum" flag in the launcher */
|
||||
MyProc->vacuumFlags = 0;
|
||||
MyProc->lwWaiting = false;
|
||||
@ -1277,6 +1279,54 @@ ProcSendSignal(int pid)
|
||||
PGSemaphoreUnlock(&proc->sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* SendProcSignal - send the signal with the reason to a process.
|
||||
*
|
||||
* The process can be a backend or an auxiliary process that has a PGPROC
|
||||
* entry, like an autovacuum worker.
|
||||
*/
|
||||
void
|
||||
SendProcSignal(PGPROC *proc, ProcSignalReason reason)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
/*
|
||||
* If the process is gone, do nothing.
|
||||
*
|
||||
* Since there's no locking, it's possible that the process detaches
|
||||
* from shared memory and exits right after this test, before we set
|
||||
* the flag and send signal. And the PGPROC entry might even be recycled
|
||||
* by a new process, so it's remotely possible that we signal a wrong
|
||||
* process. That's OK, all the signals are such that no harm is done.
|
||||
*/
|
||||
pid = proc->pid;
|
||||
if (pid == 0)
|
||||
return;
|
||||
|
||||
/* Atomically set the proper flag */
|
||||
proc->signalFlags[reason] = true;
|
||||
/* Send SIGUSR1 to the process */
|
||||
kill(pid, SIGUSR1);
|
||||
}
|
||||
|
||||
/*
|
||||
* CheckProcSignal - check to see if the particular reason has been
|
||||
* signaled, and clear the signal flag. Should be called after
|
||||
* receiving SIGUSR1.
|
||||
*/
|
||||
bool
|
||||
CheckProcSignal(ProcSignalReason reason)
|
||||
{
|
||||
/* Careful here --- don't clear flag if we haven't seen it set */
|
||||
if (MyProc->signalFlags[reason])
|
||||
{
|
||||
MyProc->signalFlags[reason] = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* SIGALRM interrupt support
|
||||
|
Reference in New Issue
Block a user