Use ModifyWaitEvent to update exit_on_postmaster_death
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 5 Mar 2025 23:26:12 +0000 (01:26 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 5 Mar 2025 23:26:12 +0000 (01:26 +0200)
This is in preparation for splitting WaitEventSet related functions to
a separate source file. That will hide the details of WaitEventSet
from WaitLatch, so it must use an exposed function instead of
modifying WaitEventSet->exit_on_postmaster_death directly.

Reviewed-by: Andres Freund <andres@anarazel.de>
Discussion: https://www.postgresql.org/message-id/8a507fb6-df28-49d3-81a5-ede180d7f0fb@iki.fi

src/backend/storage/ipc/latch.c

index cd09a10f3d118056ed47198b3f3248b61d31416e..997bcb58ff75091ae67019481631ce7b1265894d 100644 (file)
@@ -154,8 +154,9 @@ struct WaitEventSet
 /* A common WaitEventSet used to implement WaitLatch() */
 static WaitEventSet *LatchWaitSet;
 
-/* The position of the latch in LatchWaitSet. */
+/* The positions of the latch and PM death events in LatchWaitSet */
 #define LatchWaitSetLatchPos 0
+#define LatchWaitSetPostmasterDeathPos 1
 
 #ifndef WIN32
 /* Are we currently in WaitLatch? The signal handler would like to know. */
@@ -353,11 +354,18 @@ InitializeLatchWaitSet(void)
    LatchWaitSet = CreateWaitEventSet(NULL, 2);
    latch_pos = AddWaitEventToSet(LatchWaitSet, WL_LATCH_SET, PGINVALID_SOCKET,
                                  MyLatch, NULL);
-   if (IsUnderPostmaster)
-       AddWaitEventToSet(LatchWaitSet, WL_EXIT_ON_PM_DEATH,
-                         PGINVALID_SOCKET, NULL, NULL);
-
    Assert(latch_pos == LatchWaitSetLatchPos);
+
+   /*
+    * WaitLatch will modify this to WL_EXIT_ON_PM_DEATH or
+    * WL_POSTMASTER_DEATH on each call.
+    */
+   if (IsUnderPostmaster)
+   {
+       latch_pos = AddWaitEventToSet(LatchWaitSet, WL_EXIT_ON_PM_DEATH,
+                                     PGINVALID_SOCKET, NULL, NULL);
+       Assert(latch_pos == LatchWaitSetPostmasterDeathPos);
+   }
 }
 
 /*
@@ -505,8 +513,9 @@ WaitLatch(Latch *latch, int wakeEvents, long timeout,
    if (!(wakeEvents & WL_LATCH_SET))
        latch = NULL;
    ModifyWaitEvent(LatchWaitSet, LatchWaitSetLatchPos, WL_LATCH_SET, latch);
-   LatchWaitSet->exit_on_postmaster_death =
-       ((wakeEvents & WL_EXIT_ON_PM_DEATH) != 0);
+   ModifyWaitEvent(LatchWaitSet, LatchWaitSetPostmasterDeathPos,
+                   (wakeEvents & (WL_EXIT_ON_PM_DEATH | WL_POSTMASTER_DEATH)),
+                   NULL);
 
    if (WaitEventSetWait(LatchWaitSet,
                         (wakeEvents & WL_TIMEOUT) ? timeout : -1,
@@ -1027,6 +1036,21 @@ ModifyWaitEvent(WaitEventSet *set, int pos, uint32 events, Latch *latch)
    old_events = event->events;
 #endif
 
+   /*
+    * Allow switching between WL_POSTMASTER_DEATH and WL_EXIT_ON_PM_DEATH.
+    *
+    * Note that because WL_EXIT_ON_PM_DEATH is mapped to WL_POSTMASTER_DEATH
+    * in AddWaitEventToSet(), this needs to be checked before the fast-path
+    * below that checks if 'events' has changed.
+    */
+   if (event->events == WL_POSTMASTER_DEATH)
+   {
+       if (events != WL_POSTMASTER_DEATH && events != WL_EXIT_ON_PM_DEATH)
+           elog(ERROR, "cannot remove postmaster death event");
+       set->exit_on_postmaster_death = ((events & WL_EXIT_ON_PM_DEATH) != 0);
+       return;
+   }
+
    /*
     * If neither the event mask nor the associated latch changes, return
     * early. That's an important optimization for some sockets, where
@@ -1037,16 +1061,8 @@ ModifyWaitEvent(WaitEventSet *set, int pos, uint32 events, Latch *latch)
        (!(event->events & WL_LATCH_SET) || set->latch == latch))
        return;
 
-   if (event->events & WL_LATCH_SET &&
-       events != event->events)
-   {
+   if (event->events & WL_LATCH_SET && events != event->events)
        elog(ERROR, "cannot modify latch event");
-   }
-
-   if (event->events & WL_POSTMASTER_DEATH)
-   {
-       elog(ERROR, "cannot modify postmaster death event");
-   }
 
    /* FIXME: validate event mask */
    event->events = events;