]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Use EVFILT_SIGNAL for kqueue latches.
authorThomas Munro <tmunro@postgresql.org>
Sun, 28 Feb 2021 23:28:43 +0000 (12:28 +1300)
committerThomas Munro <tmunro@postgresql.org>
Mon, 1 Mar 2021 01:20:04 +0000 (14:20 +1300)
Cut down on system calls and other overheads by waiting for SIGURG
explicitly with kqueue instead of using a signal handler and self-pipe.
Affects *BSD and macOS systems.

This leaves only the poll implementation with a signal handler and the
traditional self-pipe trick.

Discussion: https://postgr.es/m/CA+hUKGJjxPDpzBE0a3hyUywBvaZuC89yx3jK9RFZgfv_KHU7gg@mail.gmail.com

src/backend/storage/ipc/latch.c

index ea6d9948abebb4760c40ffb37af7059bcbcd9168..43a5fded103bf392281cea1578ef4b2c40009502 100644 (file)
@@ -18,6 +18,8 @@
  * don't need to register a signal handler or create our own self-pipe.  We
  * assume that any system that has Linux epoll() also has Linux signalfd().
  *
+ * The kqueue() implementation waits for SIGURG with EVFILT_SIGNAL.
+ *
  * The Windows implementation uses Windows events that are inherited by all
  * postmaster child processes. There's no need for the self-pipe trick there.
  *
@@ -150,7 +152,7 @@ static volatile sig_atomic_t waiting = false;
 static int     signal_fd = -1;
 #endif
 
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
 /* Read and write ends of the self-pipe */
 static int     selfpipe_readfd = -1;
 static int     selfpipe_writefd = -1;
@@ -189,7 +191,7 @@ static inline int WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
 void
 InitializeLatchSupport(void)
 {
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
        int                     pipefd[2];
 
        if (IsUnderPostmaster)
@@ -277,6 +279,11 @@ InitializeLatchSupport(void)
                elog(FATAL, "signalfd() failed");
        ReserveExternalFD();
 #endif
+
+#ifdef WAIT_USE_KQUEUE
+       /* Ignore SIGURG, because we'll receive it via kqueue. */
+       pqsignal(SIGURG, SIG_IGN);
+#endif
 }
 
 void
@@ -300,7 +307,7 @@ InitializeLatchWaitSet(void)
 void
 ShutdownLatchSupport(void)
 {
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
        pqsignal(SIGURG, SIG_IGN);
 #endif
 
@@ -310,7 +317,7 @@ ShutdownLatchSupport(void)
                LatchWaitSet = NULL;
        }
 
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
        close(selfpipe_readfd);
        close(selfpipe_writefd);
        selfpipe_readfd = -1;
@@ -335,7 +342,7 @@ InitLatch(Latch *latch)
        latch->owner_pid = MyProcPid;
        latch->is_shared = false;
 
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
        /* Assert InitializeLatchSupport has been called in this process */
        Assert(selfpipe_readfd >= 0 && selfpipe_owner_pid == MyProcPid);
 #elif defined(WAIT_USE_WIN32)
@@ -399,7 +406,7 @@ OwnLatch(Latch *latch)
        /* Sanity checks */
        Assert(latch->is_shared);
 
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
        /* Assert InitializeLatchSupport has been called in this process */
        Assert(selfpipe_readfd >= 0 && selfpipe_owner_pid == MyProcPid);
 #endif
@@ -611,7 +618,7 @@ SetLatch(Latch *latch)
                return;
        else if (owner_pid == MyProcPid)
        {
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
                if (waiting)
                        sendSelfPipeByte();
 #else
@@ -898,13 +905,15 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
        {
                set->latch = latch;
                set->latch_pos = event->pos;
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
                event->fd = selfpipe_readfd;
 #elif defined(WAIT_USE_EPOLL)
                event->fd = signal_fd;
 #else
                event->fd = PGINVALID_SOCKET;
+#ifdef WAIT_USE_EPOLL
                return event->pos;
+#endif
 #endif
        }
        else if (events == WL_POSTMASTER_DEATH)
@@ -1125,6 +1134,18 @@ WaitEventAdjustKqueueAddPostmaster(struct kevent *k_ev, WaitEvent *event)
        AccessWaitEvent(k_ev) = event;
 }
 
+static inline void
+WaitEventAdjustKqueueAddLatch(struct kevent *k_ev, WaitEvent *event)
+{
+       /* For now latch can only be added, not removed. */
+       k_ev->ident = SIGURG;
+       k_ev->filter = EVFILT_SIGNAL;
+       k_ev->flags = EV_ADD;
+       k_ev->fflags = 0;
+       k_ev->data = 0;
+       AccessWaitEvent(k_ev) = event;
+}
+
 /*
  * old_events is the previous event mask, used to compute what has changed.
  */
@@ -1156,6 +1177,11 @@ WaitEventAdjustKqueue(WaitEventSet *set, WaitEvent *event, int old_events)
                 */
                WaitEventAdjustKqueueAddPostmaster(&k_ev[count++], event);
        }
+       else if (event->events == WL_LATCH_SET)
+       {
+               /* We detect latch wakeup using a signal event. */
+               WaitEventAdjustKqueueAddLatch(&k_ev[count++], event);
+       }
        else
        {
                /*
@@ -1163,11 +1189,9 @@ WaitEventAdjustKqueue(WaitEventSet *set, WaitEvent *event, int old_events)
                 * old event mask to the new event mask, since kevent treats readable
                 * and writable as separate events.
                 */
-               if (old_events == WL_LATCH_SET ||
-                       (old_events & WL_SOCKET_READABLE))
+               if (old_events & WL_SOCKET_READABLE)
                        old_filt_read = true;
-               if (event->events == WL_LATCH_SET ||
-                       (event->events & WL_SOCKET_READABLE))
+               if (event->events & WL_SOCKET_READABLE)
                        new_filt_read = true;
                if (old_events & WL_SOCKET_WRITEABLE)
                        old_filt_write = true;
@@ -1620,11 +1644,8 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
                occurred_events->events = 0;
 
                if (cur_event->events == WL_LATCH_SET &&
-                       cur_kqueue_event->filter == EVFILT_READ)
+                       cur_kqueue_event->filter == EVFILT_SIGNAL)
                {
-                       /* There's data in the self-pipe, clear it. */
-                       drain();
-
                        if (set->latch && set->latch->is_set)
                        {
                                occurred_events->fd = PGINVALID_SOCKET;
@@ -1999,7 +2020,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
 }
 #endif
 
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
 
 /*
  * SetLatch uses SIGURG to wake up the process waiting on the latch.