Skip to content

Commit 3e3be0e

Browse files
author
Commitfest Bot
committed
[CF 5931] Optimize ProcSignal to avoid redundant SIGUSR1 signals
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5931 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/a0b12a70-8200-4bd4-9e24-56796314bdce@app.fastmail.com Author(s): Joel Jacobson
2 parents 88824e6 + fa51810 commit 3e3be0e

File tree

2 files changed

+57
-49
lines changed

2 files changed

+57
-49
lines changed

src/backend/storage/ipc/procsignal.c

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ typedef struct
6565
pg_atomic_uint32 pss_pid;
6666
int pss_cancel_key_len; /* 0 means no cancellation is possible */
6767
uint8 pss_cancel_key[MAX_CANCEL_KEY_LENGTH];
68-
volatile sig_atomic_t pss_signalFlags[NUM_PROCSIGNALS];
69-
slock_t pss_mutex; /* protects the above fields */
68+
pg_atomic_uint32 pss_signalFlags; /* bitmask of pending signals */
69+
slock_t pss_mutex; /* protects cancel_key fields only */
7070

7171
/* Barrier-related fields (not protected by pss_mutex) */
7272
pg_atomic_uint64 pss_barrierGeneration;
@@ -105,7 +105,7 @@ struct ProcSignalHeader
105105
NON_EXEC_STATIC ProcSignalHeader *ProcSignal = NULL;
106106
static ProcSignalSlot *MyProcSignalSlot = NULL;
107107

108-
static bool CheckProcSignal(ProcSignalReason reason);
108+
static bool HasProcSignalFlag(uint32 flags, ProcSignalReason reason);
109109
static void CleanupProcSignalState(int status, Datum arg);
110110
static void ResetProcSignalBarrierBits(uint32 flags);
111111

@@ -150,7 +150,7 @@ ProcSignalShmemInit(void)
150150
SpinLockInit(&slot->pss_mutex);
151151
pg_atomic_init_u32(&slot->pss_pid, 0);
152152
slot->pss_cancel_key_len = 0;
153-
MemSet(slot->pss_signalFlags, 0, sizeof(slot->pss_signalFlags));
153+
pg_atomic_init_u32(&slot->pss_signalFlags, 0);
154154
pg_atomic_init_u64(&slot->pss_barrierGeneration, PG_UINT64_MAX);
155155
pg_atomic_init_u32(&slot->pss_barrierCheckMask, 0);
156156
ConditionVariableInit(&slot->pss_barrierCV);
@@ -182,7 +182,7 @@ ProcSignalInit(const uint8 *cancel_key, int cancel_key_len)
182182
old_pss_pid = pg_atomic_read_u32(&slot->pss_pid);
183183

184184
/* Clear out any leftover signal reasons */
185-
MemSet(slot->pss_signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t));
185+
pg_atomic_write_u32(&slot->pss_signalFlags, 0);
186186

187187
/*
188188
* Initialize barrier state. Since we're a brand-new process, there
@@ -212,7 +212,7 @@ ProcSignalInit(const uint8 *cancel_key, int cancel_key_len)
212212
elog(LOG, "process %d taking over ProcSignal slot %d, but it's not empty",
213213
MyProcPid, MyProcNumber);
214214

215-
/* Remember slot location for CheckProcSignal */
215+
/* Remember slot location for HasProcSignalFlag */
216216
MyProcSignalSlot = slot;
217217

218218
/* Set up to release the slot on process exit */
@@ -294,10 +294,15 @@ SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
294294
if (pg_atomic_read_u32(&slot->pss_pid) == pid)
295295
{
296296
/* Atomically set the proper flag */
297-
slot->pss_signalFlags[reason] = true;
297+
uint32 oldflags = pg_atomic_fetch_or_u32(&slot->pss_signalFlags,
298+
(uint32) 1 << reason);
299+
298300
SpinLockRelease(&slot->pss_mutex);
299-
/* Send signal */
300-
return kill(pid, SIGUSR1);
301+
/* Send signal only if there were no pending signals before this. */
302+
if (oldflags == 0)
303+
return kill(pid, SIGUSR1);
304+
else
305+
return 0;
301306
}
302307
SpinLockRelease(&slot->pss_mutex);
303308
}
@@ -322,10 +327,15 @@ SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
322327
if (pg_atomic_read_u32(&slot->pss_pid) == pid)
323328
{
324329
/* Atomically set the proper flag */
325-
slot->pss_signalFlags[reason] = true;
330+
uint32 oldflags = pg_atomic_fetch_or_u32(&slot->pss_signalFlags,
331+
(uint32) 1 << reason);
332+
326333
SpinLockRelease(&slot->pss_mutex);
327-
/* Send signal */
328-
return kill(pid, SIGUSR1);
334+
/* Send signal only if there were no pending signals before this. */
335+
if (oldflags == 0)
336+
return kill(pid, SIGUSR1);
337+
else
338+
return 0;
329339
}
330340
SpinLockRelease(&slot->pss_mutex);
331341
}
@@ -404,9 +414,13 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
404414
if (pid != 0)
405415
{
406416
/* see SendProcSignal for details */
407-
slot->pss_signalFlags[PROCSIG_BARRIER] = true;
417+
uint32 oldflags = pg_atomic_fetch_or_u32(&slot->pss_signalFlags,
418+
(uint32) 1 << PROCSIG_BARRIER);
419+
408420
SpinLockRelease(&slot->pss_mutex);
409-
kill(pid, SIGUSR1);
421+
/* Send signal only if there were no pending signals before this. */
422+
if (oldflags == 0)
423+
kill(pid, SIGUSR1);
410424
}
411425
else
412426
SpinLockRelease(&slot->pss_mutex);
@@ -641,30 +655,13 @@ ResetProcSignalBarrierBits(uint32 flags)
641655
}
642656

643657
/*
644-
* CheckProcSignal - check to see if a particular reason has been
645-
* signaled, and clear the signal flag. Should be called after receiving
646-
* SIGUSR1.
658+
* HasProcSignalFlag - check to see if a particular reason has been
659+
* signaled in the given flags bitmask.
647660
*/
648661
static bool
649-
CheckProcSignal(ProcSignalReason reason)
662+
HasProcSignalFlag(uint32 flags, ProcSignalReason reason)
650663
{
651-
volatile ProcSignalSlot *slot = MyProcSignalSlot;
652-
653-
if (slot != NULL)
654-
{
655-
/*
656-
* Careful here --- don't clear flag if we haven't seen it set.
657-
* pss_signalFlags is of type "volatile sig_atomic_t" to allow us to
658-
* read it here safely, without holding the spinlock.
659-
*/
660-
if (slot->pss_signalFlags[reason])
661-
{
662-
slot->pss_signalFlags[reason] = false;
663-
return true;
664-
}
665-
}
666-
667-
return false;
664+
return (flags & ((uint32) 1 << reason)) != 0;
668665
}
669666

670667
/*
@@ -673,46 +670,54 @@ CheckProcSignal(ProcSignalReason reason)
673670
void
674671
procsignal_sigusr1_handler(SIGNAL_ARGS)
675672
{
676-
if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
673+
uint32 flags;
674+
675+
/* Atomically consume all pending signals */
676+
if (MyProcSignalSlot)
677+
flags = pg_atomic_exchange_u32(&MyProcSignalSlot->pss_signalFlags, 0);
678+
else
679+
flags = 0;
680+
681+
if (HasProcSignalFlag(flags, PROCSIG_CATCHUP_INTERRUPT))
677682
HandleCatchupInterrupt();
678683

679-
if (CheckProcSignal(PROCSIG_NOTIFY_INTERRUPT))
684+
if (HasProcSignalFlag(flags, PROCSIG_NOTIFY_INTERRUPT))
680685
HandleNotifyInterrupt();
681686

682-
if (CheckProcSignal(PROCSIG_PARALLEL_MESSAGE))
687+
if (HasProcSignalFlag(flags, PROCSIG_PARALLEL_MESSAGE))
683688
HandleParallelMessageInterrupt();
684689

685-
if (CheckProcSignal(PROCSIG_WALSND_INIT_STOPPING))
690+
if (HasProcSignalFlag(flags, PROCSIG_WALSND_INIT_STOPPING))
686691
HandleWalSndInitStopping();
687692

688-
if (CheckProcSignal(PROCSIG_BARRIER))
693+
if (HasProcSignalFlag(flags, PROCSIG_BARRIER))
689694
HandleProcSignalBarrierInterrupt();
690695

691-
if (CheckProcSignal(PROCSIG_LOG_MEMORY_CONTEXT))
696+
if (HasProcSignalFlag(flags, PROCSIG_LOG_MEMORY_CONTEXT))
692697
HandleLogMemoryContextInterrupt();
693698

694-
if (CheckProcSignal(PROCSIG_PARALLEL_APPLY_MESSAGE))
699+
if (HasProcSignalFlag(flags, PROCSIG_PARALLEL_APPLY_MESSAGE))
695700
HandleParallelApplyMessageInterrupt();
696701

697-
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_DATABASE))
702+
if (HasProcSignalFlag(flags, PROCSIG_RECOVERY_CONFLICT_DATABASE))
698703
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_DATABASE);
699704

700-
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_TABLESPACE))
705+
if (HasProcSignalFlag(flags, PROCSIG_RECOVERY_CONFLICT_TABLESPACE))
701706
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_TABLESPACE);
702707

703-
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_LOCK))
708+
if (HasProcSignalFlag(flags, PROCSIG_RECOVERY_CONFLICT_LOCK))
704709
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_LOCK);
705710

706-
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_SNAPSHOT))
711+
if (HasProcSignalFlag(flags, PROCSIG_RECOVERY_CONFLICT_SNAPSHOT))
707712
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_SNAPSHOT);
708713

709-
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT))
714+
if (HasProcSignalFlag(flags, PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT))
710715
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT);
711716

712-
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK))
717+
if (HasProcSignalFlag(flags, PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK))
713718
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
714719

715-
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN))
720+
if (HasProcSignalFlag(flags, PROCSIG_RECOVERY_CONFLICT_BUFFERPIN))
716721
HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
717722

718723
SetLatch(MyLatch);

src/include/storage/procsignal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ typedef enum
5151

5252
#define NUM_PROCSIGNALS (PROCSIG_RECOVERY_CONFLICT_LAST + 1)
5353

54+
StaticAssertDecl(NUM_PROCSIGNALS <= 32,
55+
"NUM_PROCSIGNALS must fit into ProcSignalSlot.pss_signalFlags");
56+
5457
typedef enum
5558
{
5659
PROCSIGNAL_BARRIER_SMGRRELEASE, /* ask smgr to close files */

0 commit comments

Comments
 (0)