Use condition variables for ProcSignalBarriers.
authorThomas Munro <tmunro@postgresql.org>
Mon, 1 Mar 2021 03:26:22 +0000 (16:26 +1300)
committerThomas Munro <tmunro@postgresql.org>
Mon, 1 Mar 2021 04:23:43 +0000 (17:23 +1300)
Instead of a poll/sleep loop, use a condition variable for precise
wake-up whenever a backend's pss_barrierGeneration advances.

Discussion: https://postgr.es/m/CA+hUKGLdemy2gBm80kz20GTe6hNVwoErE8KwcJk6-U56oStjtg@mail.gmail.com

src/backend/storage/ipc/procsignal.c

index ed97f4a3e97fafa337f759d744f08b342e995f97..8e5ee49fbd7410b55b1161c6534280bd28f24572 100644 (file)
@@ -23,6 +23,7 @@
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "replication/walsender.h"
+#include "storage/condition_variable.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
 #include "storage/proc.h"
  */
 typedef struct
 {
-   pid_t       pss_pid;
-   sig_atomic_t pss_signalFlags[NUM_PROCSIGNALS];
+   volatile pid_t      pss_pid;
+   volatile sig_atomic_t pss_signalFlags[NUM_PROCSIGNALS];
    pg_atomic_uint64 pss_barrierGeneration;
    pg_atomic_uint32 pss_barrierCheckMask;
+   ConditionVariable pss_barrierCV;
 } ProcSignalSlot;
 
 /*
@@ -93,7 +95,7 @@ typedef struct
    ((flags) &= ~(((uint32) 1) << (uint32) (type)))
 
 static ProcSignalHeader *ProcSignal = NULL;
-static volatile ProcSignalSlot *MyProcSignalSlot = NULL;
+static ProcSignalSlot *MyProcSignalSlot = NULL;
 
 static bool CheckProcSignal(ProcSignalReason reason);
 static void CleanupProcSignalState(int status, Datum arg);
@@ -142,6 +144,7 @@ ProcSignalShmemInit(void)
            MemSet(slot->pss_signalFlags, 0, sizeof(slot->pss_signalFlags));
            pg_atomic_init_u64(&slot->pss_barrierGeneration, PG_UINT64_MAX);
            pg_atomic_init_u32(&slot->pss_barrierCheckMask, 0);
+           ConditionVariableInit(&slot->pss_barrierCV);
        }
    }
 }
@@ -156,7 +159,7 @@ ProcSignalShmemInit(void)
 void
 ProcSignalInit(int pss_idx)
 {
-   volatile ProcSignalSlot *slot;
+   ProcSignalSlot *slot;
    uint64      barrier_generation;
 
    Assert(pss_idx >= 1 && pss_idx <= NumProcSignalSlots);
@@ -208,7 +211,7 @@ static void
 CleanupProcSignalState(int status, Datum arg)
 {
    int         pss_idx = DatumGetInt32(arg);
-   volatile ProcSignalSlot *slot;
+   ProcSignalSlot *slot;
 
    slot = &ProcSignal->psh_slot[pss_idx - 1];
    Assert(slot == MyProcSignalSlot);
@@ -237,6 +240,7 @@ CleanupProcSignalState(int status, Datum arg)
     * no barrier waits block on it.
     */
    pg_atomic_write_u64(&slot->pss_barrierGeneration, PG_UINT64_MAX);
+   ConditionVariableBroadcast(&slot->pss_barrierCV);
 
    slot->pss_pid = 0;
 }
@@ -391,13 +395,11 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 void
 WaitForProcSignalBarrier(uint64 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];
+       ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
        uint64      oldval;
 
        /*
@@ -409,20 +411,11 @@ WaitForProcSignalBarrier(uint64 generation)
        oldval = pg_atomic_read_u64(&slot->pss_barrierGeneration);
        while (oldval < generation)
        {
-           int         events;
-
-           CHECK_FOR_INTERRUPTS();
-
-           events =
-               WaitLatch(MyLatch,
-                         WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
-                         timeout, WAIT_EVENT_PROC_SIGNAL_BARRIER);
-           ResetLatch(MyLatch);
-
+           ConditionVariableSleep(&slot->pss_barrierCV,
+                                  WAIT_EVENT_PROC_SIGNAL_BARRIER);
            oldval = pg_atomic_read_u64(&slot->pss_barrierGeneration);
-           if (events & WL_TIMEOUT)
-               timeout = Min(timeout * 2, 1000L);
        }
+       ConditionVariableCancelSleep();
    }
 
    /*
@@ -589,6 +582,7 @@ ProcessProcSignalBarrier(void)
     * next called.
     */
    pg_atomic_write_u64(&MyProcSignalSlot->pss_barrierGeneration, shared_gen);
+   ConditionVariableBroadcast(&MyProcSignalSlot->pss_barrierCV);
 }
 
 /*