From 6e2ad6419c5f9005412113630d6a7d64f884df42 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Thu, 19 Nov 2020 15:35:04 +1300
Subject: [PATCH v5 4/5] Use EVFILT_SIGNAL for kqueue latches.

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 | 55 +++++++++++++++++++++++----------
 1 file changed, 38 insertions(+), 17 deletions(-)

diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index a2d3505018..c9b57353be 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -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)
@@ -279,6 +281,11 @@ InitializeLatchSupport(void)
 		ReserveExternalFD();
 	}
 #endif
+
+#ifdef WAIT_USE_KQUEUE
+	/* Ignore SIGURG, because we'll receive it via kqueue. */
+	pqsignal(SIGURG, SIG_IGN);
+#endif
 }
 
 void
@@ -302,7 +309,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
 
@@ -312,7 +319,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;
@@ -337,7 +344,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)
@@ -401,7 +408,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
@@ -613,7 +620,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
@@ -919,13 +926,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)
@@ -1146,6 +1155,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.
  */
@@ -1177,6 +1198,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
 	{
 		/*
@@ -1184,11 +1210,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;
@@ -1641,11 +1665,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;
@@ -2020,7 +2041,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.
-- 
2.30.0

