uint64
EmitProcSignalBarrier(ProcSignalBarrierType type)
{
- uint64 flagbit = UINT64CONST(1) << (uint64) type;
+ uint32 flagbit = 1 << (uint32) type;
uint64 generation;
/*
pid_t pid = slot->pss_pid;
if (pid != 0)
+ {
+ /* see SendProcSignal for details */
+ slot->pss_signalFlags[PROCSIG_BARRIER] = true;
kill(pid, SIGUSR1);
+ }
}
return generation;
{
long timeout = 125L;
+ Assert(generation <= pg_atomic_read_u64(&ProcSignal->psh_barrierGeneration));
+
for (int i = NumProcSignalSlots - 1; i >= 0; i--)
{
volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
pg_memory_barrier();
}
+/*
+ * Handle receipt of an interrupt indicating a global barrier event.
+ *
+ * All the actual work is deferred to ProcessProcSignalBarrier(), because we
+ * cannot safely access the barrier generation inside the signal handler as
+ * 64bit atomics might use spinlock based emulation, even for reads. As this
+ * routine only gets called when PROCSIG_BARRIER is sent that won't cause a
+ * lot fo unnecessary work.
+ */
+static void
+HandleProcSignalBarrierInterrupt(void)
+{
+ InterruptPending = true;
+ ProcSignalBarrierPending = true;
+ /* latch will be set by procsignal_sigusr1_handler */
+}
+
/*
* Perform global barrier related interrupt checking.
*
void
ProcessProcSignalBarrier(void)
{
- uint64 generation;
+ uint64 local_gen;
+ uint64 shared_gen;
uint32 flags;
+ Assert(MyProcSignalSlot);
+
/* Exit quickly if there's no work to do. */
if (!ProcSignalBarrierPending)
return;
ProcSignalBarrierPending = false;
/*
- * Read the current barrier generation, and then get the flags that are
- * set for this backend. Note that pg_atomic_exchange_u32 is a full
- * barrier, so we're guaranteed that the read of the barrier generation
- * happens before we atomically extract the flags, and that any subsequent
- * state changes happen afterward.
+ * It's not unlikely to process multiple barriers at once, before the
+ * signals for all the barriers have arrived. To avoid unnecessary work in
+ * response to subsequent signals, exit early if we already have processed
+ * all of them.
+ */
+ local_gen = pg_atomic_read_u64(&MyProcSignalSlot->pss_barrierGeneration);
+ shared_gen = pg_atomic_read_u64(&ProcSignal->psh_barrierGeneration);
+
+ Assert(local_gen <= shared_gen);
+
+ if (local_gen == shared_gen)
+ return;
+
+ /*
+ * Get and clear the flags that are set for this backend. Note that
+ * pg_atomic_exchange_u32 is a full barrier, so we're guaranteed that the
+ * read of the barrier generation above happens before we atomically
+ * extract the flags, and that any subsequent state changes happen
+ * afterward.
*/
- generation = pg_atomic_read_u64(&ProcSignal->psh_barrierGeneration);
flags = pg_atomic_exchange_u32(&MyProcSignalSlot->pss_barrierCheckMask, 0);
/*
* things have changed further, it'll get fixed up when this function is
* next called.
*/
- pg_atomic_write_u64(&MyProcSignalSlot->pss_barrierGeneration, generation);
+ pg_atomic_write_u64(&MyProcSignalSlot->pss_barrierGeneration, shared_gen);
}
static void
return false;
}
-/*
- * CheckProcSignalBarrier - check for new barriers we need to absorb
- */
-static bool
-CheckProcSignalBarrier(void)
-{
- volatile ProcSignalSlot *slot = MyProcSignalSlot;
-
- if (slot != NULL)
- {
- uint64 mygen;
- uint64 curgen;
-
- mygen = pg_atomic_read_u64(&slot->pss_barrierGeneration);
- curgen = pg_atomic_read_u64(&ProcSignal->psh_barrierGeneration);
- return (mygen != curgen);
- }
-
- return false;
-}
-
/*
* procsignal_sigusr1_handler - handle SIGUSR1 signal.
*/
if (CheckProcSignal(PROCSIG_WALSND_INIT_STOPPING))
HandleWalSndInitStopping();
+ if (CheckProcSignal(PROCSIG_BARRIER))
+ HandleProcSignalBarrierInterrupt();
+
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_DATABASE))
RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_DATABASE);
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN))
RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
- if (CheckProcSignalBarrier())
- {
- InterruptPending = true;
- ProcSignalBarrierPending = true;
- }
-
SetLatch(MyLatch);
latch_sigusr1_handler();