Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7b05b3f

Browse files
committed
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.
1 parent 9edd720 commit 7b05b3f

File tree

10 files changed

+143
-45
lines changed

10 files changed

+143
-45
lines changed

src/backend/access/transam/twophase.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.48 2008/11/19 10:34:50 heikki Exp $
10+
* $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.49 2008/12/09 14:28:20 heikki Exp $
1111
*
1212
* NOTES
1313
* Each global transaction is associated with a global transaction
@@ -287,6 +287,7 @@ MarkAsPreparing(TransactionId xid, const char *gid,
287287
gxact->proc.databaseId = databaseid;
288288
gxact->proc.roleId = owner;
289289
gxact->proc.inCommit = false;
290+
MemSet(gxact->proc.signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t));
290291
gxact->proc.vacuumFlags = 0;
291292
gxact->proc.lwWaiting = false;
292293
gxact->proc.lwExclusive = false;

src/backend/commands/async.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.142 2008/11/02 01:45:27 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.143 2008/12/09 14:28:20 heikki Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -915,9 +915,10 @@ EnableNotifyInterrupt(void)
915915
* a frontend command. Signal handler execution of inbound notifies
916916
* is disabled until the next EnableNotifyInterrupt call.
917917
*
918-
* The SIGUSR1 signal handler also needs to call this, so as to
919-
* prevent conflicts if one signal interrupts the other. So we
920-
* must return the previous state of the flag.
918+
* This also needs to be called when SIGUSR1 with
919+
* PROCSIG_CATCHUP_INTERRUPT is received, so as to prevent conflicts
920+
* if one signal interrupts the other. So we must return the previous
921+
* state of the flag.
921922
*/
922923
bool
923924
DisableNotifyInterrupt(void)
@@ -954,7 +955,7 @@ ProcessIncomingNotify(void)
954955
nulls[Natts_pg_listener];
955956
bool catchup_enabled;
956957

957-
/* Must prevent SIGUSR1 interrupt while I am running */
958+
/* Must prevent catchup interrupt while I am running */
958959
catchup_enabled = DisableCatchupInterrupt();
959960

960961
if (Trace_notify)

src/backend/postmaster/autovacuum.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
*
5656
*
5757
* IDENTIFICATION
58-
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.88 2008/12/04 11:42:24 heikki Exp $
58+
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.89 2008/12/09 14:28:20 heikki Exp $
5959
*
6060
*-------------------------------------------------------------------------
6161
*/
@@ -1477,7 +1477,7 @@ AutoVacWorkerMain(int argc, char *argv[])
14771477
pqsignal(SIGALRM, handle_sig_alarm);
14781478

14791479
pqsignal(SIGPIPE, SIG_IGN);
1480-
pqsignal(SIGUSR1, CatchupInterruptHandler);
1480+
pqsignal(SIGUSR1, proc_sigusr1_handler);
14811481
/* We don't listen for async notifies */
14821482
pqsignal(SIGUSR2, SIG_IGN);
14831483
pqsignal(SIGFPE, FloatExceptionHandler);

src/backend/storage/ipc/sinval.c

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinval.c,v 1.86 2008/06/19 21:32:56 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinval.c,v 1.87 2008/12/09 14:28:20 heikki Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -26,8 +26,8 @@
2626
* Because backends sitting idle will not be reading sinval events, we
2727
* need a way to give an idle backend a swift kick in the rear and make
2828
* it catch up before the sinval queue overflows and forces it to go
29-
* through a cache reset exercise. This is done by sending SIGUSR1
30-
* to any backend that gets too far behind.
29+
* through a cache reset exercise. This is done by sending
30+
* PROCSIG_CATCHUP_INTERRUPT to any backend that gets too far behind.
3131
*
3232
* State for catchup events consists of two flags: one saying whether
3333
* the signal handler is currently allowed to call ProcessCatchupEvent
@@ -144,9 +144,9 @@ ReceiveSharedInvalidMessages(
144144

145145

146146
/*
147-
* CatchupInterruptHandler
147+
* HandleCatchupInterrupt
148148
*
149-
* This is the signal handler for SIGUSR1.
149+
* This is called when PROCSIG_CATCHUP_INTERRUPT signal is received.
150150
*
151151
* If we are idle (catchupInterruptEnabled is set), we can safely
152152
* invoke ProcessCatchupEvent directly. Otherwise, just set a flag
@@ -156,13 +156,11 @@ ReceiveSharedInvalidMessages(
156156
* since there's no longer any reason to do anything.)
157157
*/
158158
void
159-
CatchupInterruptHandler(SIGNAL_ARGS)
159+
HandleCatchupInterrupt(void)
160160
{
161-
int save_errno = errno;
162-
163161
/*
164-
* Note: this is a SIGNAL HANDLER. You must be very wary what you do
165-
* here.
162+
* Note: this is called by a SIGNAL HANDLER.
163+
* You must be very wary what you do here.
166164
*/
167165

168166
/* Don't joggle the elbow of proc_exit */
@@ -216,8 +214,6 @@ CatchupInterruptHandler(SIGNAL_ARGS)
216214
*/
217215
catchupInterruptOccurred = 1;
218216
}
219-
220-
errno = save_errno;
221217
}
222218

223219
/*
@@ -289,7 +285,8 @@ DisableCatchupInterrupt(void)
289285
/*
290286
* ProcessCatchupEvent
291287
*
292-
* Respond to a catchup event (SIGUSR1) from another backend.
288+
* Respond to a catchup event (PROCSIG_CATCHUP_INTERRUPT) from another
289+
* backend.
293290
*
294291
* This is called either directly from the SIGUSR1 signal handler,
295292
* or the next time control reaches the outer idle loop (assuming

src/backend/storage/ipc/sinvaladt.c

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.74 2008/07/18 14:45:48 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.75 2008/12/09 14:28:20 heikki Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -21,6 +21,7 @@
2121
#include "storage/backendid.h"
2222
#include "storage/ipc.h"
2323
#include "storage/proc.h"
24+
#include "storage/procarray.h"
2425
#include "storage/shmem.h"
2526
#include "storage/sinvaladt.h"
2627
#include "storage/spin.h"
@@ -136,9 +137,9 @@
136137
/* Per-backend state in shared invalidation structure */
137138
typedef struct ProcState
138139
{
139-
/* procPid is zero in an inactive ProcState array entry. */
140-
pid_t procPid; /* PID of backend, for signaling */
141-
/* nextMsgNum is meaningless if procPid == 0 or resetState is true. */
140+
/* proc is NULL in an inactive ProcState array entry. */
141+
PGPROC *proc; /* PGPROC entry of backend, for signaling */
142+
/* nextMsgNum is meaningless if proc == NULL or resetState is true. */
142143
int nextMsgNum; /* next message number to read */
143144
bool resetState; /* backend needs to reset its state */
144145
bool signaled; /* backend has been sent catchup signal */
@@ -235,7 +236,7 @@ CreateSharedInvalidationState(void)
235236
/* Mark all backends inactive, and initialize nextLXID */
236237
for (i = 0; i < shmInvalBuffer->maxBackends; i++)
237238
{
238-
shmInvalBuffer->procState[i].procPid = 0; /* inactive */
239+
shmInvalBuffer->procState[i].proc = NULL; /* inactive */
239240
shmInvalBuffer->procState[i].nextMsgNum = 0; /* meaningless */
240241
shmInvalBuffer->procState[i].resetState = false;
241242
shmInvalBuffer->procState[i].signaled = false;
@@ -266,7 +267,7 @@ SharedInvalBackendInit(void)
266267
/* Look for a free entry in the procState array */
267268
for (index = 0; index < segP->lastBackend; index++)
268269
{
269-
if (segP->procState[index].procPid == 0) /* inactive slot? */
270+
if (segP->procState[index].proc == NULL) /* inactive slot? */
270271
{
271272
stateP = &segP->procState[index];
272273
break;
@@ -278,7 +279,7 @@ SharedInvalBackendInit(void)
278279
if (segP->lastBackend < segP->maxBackends)
279280
{
280281
stateP = &segP->procState[segP->lastBackend];
281-
Assert(stateP->procPid == 0);
282+
Assert(stateP->proc == NULL);
282283
segP->lastBackend++;
283284
}
284285
else
@@ -303,7 +304,7 @@ SharedInvalBackendInit(void)
303304
nextLocalTransactionId = stateP->nextLXID;
304305

305306
/* mark myself active, with all extant messages already read */
306-
stateP->procPid = MyProcPid;
307+
stateP->proc = MyProc;
307308
stateP->nextMsgNum = segP->maxMsgNum;
308309
stateP->resetState = false;
309310
stateP->signaled = false;
@@ -341,15 +342,15 @@ CleanupInvalidationState(int status, Datum arg)
341342
stateP->nextLXID = nextLocalTransactionId;
342343

343344
/* Mark myself inactive */
344-
stateP->procPid = 0;
345+
stateP->proc = NULL;
345346
stateP->nextMsgNum = 0;
346347
stateP->resetState = false;
347348
stateP->signaled = false;
348349

349350
/* Recompute index of last active backend */
350351
for (i = segP->lastBackend; i > 0; i--)
351352
{
352-
if (segP->procState[i - 1].procPid != 0)
353+
if (segP->procState[i - 1].proc != NULL)
353354
break;
354355
}
355356
segP->lastBackend = i;
@@ -374,7 +375,7 @@ BackendIdIsActive(int backendID)
374375
{
375376
ProcState *stateP = &segP->procState[backendID - 1];
376377

377-
result = (stateP->procPid != 0);
378+
result = (stateP->proc != NULL);
378379
}
379380
else
380381
result = false;
@@ -590,7 +591,7 @@ SICleanupQueue(bool callerHasWriteLock, int minFree)
590591
int n = stateP->nextMsgNum;
591592

592593
/* Ignore if inactive or already in reset state */
593-
if (stateP->procPid == 0 || stateP->resetState)
594+
if (stateP->proc == NULL || stateP->resetState)
594595
continue;
595596

596597
/*
@@ -644,18 +645,20 @@ SICleanupQueue(bool callerHasWriteLock, int minFree)
644645
segP->nextThreshold = (numMsgs / CLEANUP_QUANTUM + 1) * CLEANUP_QUANTUM;
645646

646647
/*
647-
* Lastly, signal anyone who needs a catchup interrupt. Since kill()
648-
* might not be fast, we don't want to hold locks while executing it.
648+
* Lastly, signal anyone who needs a catchup interrupt. Since
649+
* SendProcSignal() might not be fast, we don't want to hold locks while
650+
* executing it.
649651
*/
650652
if (needSig)
651653
{
652-
pid_t his_pid = needSig->procPid;
654+
PGPROC *his_proc = needSig->proc;
653655

654656
needSig->signaled = true;
655657
LWLockRelease(SInvalReadLock);
656658
LWLockRelease(SInvalWriteLock);
657-
elog(DEBUG4, "sending sinval catchup signal to PID %d", (int) his_pid);
658-
kill(his_pid, SIGUSR1);
659+
elog(DEBUG4, "sending sinval catchup signal to PID %d",
660+
(int) his_proc->pid);
661+
SendProcSignal(his_proc, PROCSIG_CATCHUP_INTERRUPT);
659662
if (callerHasWriteLock)
660663
LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE);
661664
}

src/backend/storage/lmgr/proc.c

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.202 2008/11/02 21:24:52 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.203 2008/12/09 14:28:20 heikki Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -289,6 +289,7 @@ InitProcess(void)
289289
MyProc->databaseId = InvalidOid;
290290
MyProc->roleId = InvalidOid;
291291
MyProc->inCommit = false;
292+
MemSet(MyProc->signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t));
292293
MyProc->vacuumFlags = 0;
293294
if (IsAutoVacuumWorkerProcess())
294295
MyProc->vacuumFlags |= PROC_IS_AUTOVACUUM;
@@ -428,6 +429,7 @@ InitAuxiliaryProcess(void)
428429
MyProc->databaseId = InvalidOid;
429430
MyProc->roleId = InvalidOid;
430431
MyProc->inCommit = false;
432+
MemSet(MyProc->signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t));
431433
/* we don't set the "is autovacuum" flag in the launcher */
432434
MyProc->vacuumFlags = 0;
433435
MyProc->lwWaiting = false;
@@ -1277,6 +1279,54 @@ ProcSendSignal(int pid)
12771279
PGSemaphoreUnlock(&proc->sem);
12781280
}
12791281

1282+
/*
1283+
* SendProcSignal - send the signal with the reason to a process.
1284+
*
1285+
* The process can be a backend or an auxiliary process that has a PGPROC
1286+
* entry, like an autovacuum worker.
1287+
*/
1288+
void
1289+
SendProcSignal(PGPROC *proc, ProcSignalReason reason)
1290+
{
1291+
pid_t pid;
1292+
1293+
/*
1294+
* If the process is gone, do nothing.
1295+
*
1296+
* Since there's no locking, it's possible that the process detaches
1297+
* from shared memory and exits right after this test, before we set
1298+
* the flag and send signal. And the PGPROC entry might even be recycled
1299+
* by a new process, so it's remotely possible that we signal a wrong
1300+
* process. That's OK, all the signals are such that no harm is done.
1301+
*/
1302+
pid = proc->pid;
1303+
if (pid == 0)
1304+
return;
1305+
1306+
/* Atomically set the proper flag */
1307+
proc->signalFlags[reason] = true;
1308+
/* Send SIGUSR1 to the process */
1309+
kill(pid, SIGUSR1);
1310+
}
1311+
1312+
/*
1313+
* CheckProcSignal - check to see if the particular reason has been
1314+
* signaled, and clear the signal flag. Should be called after
1315+
* receiving SIGUSR1.
1316+
*/
1317+
bool
1318+
CheckProcSignal(ProcSignalReason reason)
1319+
{
1320+
/* Careful here --- don't clear flag if we haven't seen it set */
1321+
if (MyProc->signalFlags[reason])
1322+
{
1323+
MyProc->signalFlags[reason] = false;
1324+
return true;
1325+
}
1326+
1327+
return false;
1328+
}
1329+
12801330

12811331
/*****************************************************************************
12821332
* SIGALRM interrupt support

src/backend/tcop/postgres.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.558 2008/11/30 20:51:25 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.559 2008/12/09 14:28:20 heikki Exp $
1212
*
1313
* NOTES
1414
* this is the "main" module of the postgres backend and
@@ -2436,6 +2436,23 @@ drop_unnamed_stmt(void)
24362436
* --------------------------------
24372437
*/
24382438

2439+
/*
2440+
* proc_sigusr1_handler - handle SIGUSR1 signal.
2441+
*
2442+
* SIGUSR1 is multiplexed to handle multiple different events. The signalFlags
2443+
* array in PGPROC indicates which events have been signaled.
2444+
*/
2445+
void
2446+
proc_sigusr1_handler(SIGNAL_ARGS)
2447+
{
2448+
int save_errno = errno;
2449+
2450+
if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
2451+
HandleCatchupInterrupt();
2452+
2453+
errno = save_errno;
2454+
}
2455+
24392456
/*
24402457
* quickdie() occurs when signalled SIGQUIT by the postmaster.
24412458
*
@@ -3180,7 +3197,7 @@ PostgresMain(int argc, char *argv[], const char *username)
31803197
* of output during who-knows-what operation...
31813198
*/
31823199
pqsignal(SIGPIPE, SIG_IGN);
3183-
pqsignal(SIGUSR1, CatchupInterruptHandler);
3200+
pqsignal(SIGUSR1, proc_sigusr1_handler);
31843201
pqsignal(SIGUSR2, NotifyInterruptHandler);
31853202
pqsignal(SIGFPE, FloatExceptionHandler);
31863203

0 commit comments

Comments
 (0)