From 7ceb93c7602ffb80ae32bbd87705dc638640c38a Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Tue, 6 Dec 2022 16:40:48 +1300
Subject: [PATCH v4 4/5] Allow socket WaitEvents to be temporarily blocked.

Allow ModifyWaitEvent(.., ..., 0, ...) as a way to suppress events from
a socket that we are not interested in.  This also blocks event errors
from being reported.  Another call to ModifyWaitEvent() can be used to
reenable events.

For kqueue, no change other than removing an assertion, because the code
already deletes all events for 0 (that falls out of having separate
events for read and write).

For epoll, teach ModifyWaitEvent() calls to delete and re-add to
transition between non-zero and zero event masks.

For poll, use fd -1 (allowed by POSIX for an empty entry) to make sure
we don't get any events.

For Windows, suppress the request for FD_CLOSE, which conveys errors.

Reviewed-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/CA%2BhUKG%2BZ-HpOj1JsO9eWUP%2Bar7npSVinsC_npxSy%2BjdOMsx%3DGg%40mail.gmail.com
---
 src/backend/storage/ipc/latch.c | 36 ++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index 51c239eefa..1d6fe69ef7 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -1008,14 +1008,14 @@ void
 ModifyWaitEvent(WaitEventSet *set, int pos, uint32 events, Latch *latch)
 {
 	WaitEvent  *event;
-#if defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_KQUEUE) || defined(WAIT_USE_EPOLL)
 	int			old_events;
 #endif
 
 	Assert(pos < set->nevents);
 
 	event = &set->events[pos];
-#if defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_KQUEUE) || defined(WAIT_USE_EPOLL)
 	old_events = event->events;
 #endif
 
@@ -1065,7 +1065,12 @@ ModifyWaitEvent(WaitEventSet *set, int pos, uint32 events, Latch *latch)
 	}
 
 #if defined(WAIT_USE_EPOLL)
-	WaitEventAdjustEpoll(set, event, EPOLL_CTL_MOD);
+	if (events == 0 && old_events != 0)
+		WaitEventAdjustEpoll(set, event, EPOLL_CTL_DEL);
+	else if (events != 0 && old_events == 0)
+		WaitEventAdjustEpoll(set, event, EPOLL_CTL_ADD);
+	else
+		WaitEventAdjustEpoll(set, event, EPOLL_CTL_MOD);
 #elif defined(WAIT_USE_KQUEUE)
 	WaitEventAdjustKqueue(set, event, old_events);
 #elif defined(WAIT_USE_POLL)
@@ -1103,9 +1108,6 @@ WaitEventAdjustEpoll(WaitEventSet *set, WaitEvent *event, int action)
 	else
 	{
 		Assert(event->fd != PGINVALID_SOCKET);
-		Assert(event->events & (WL_SOCKET_READABLE |
-								WL_SOCKET_WRITEABLE |
-								WL_SOCKET_CLOSED));
 
 		if (event->events & WL_SOCKET_READABLE)
 			epoll_ev.events |= EPOLLIN;
@@ -1149,6 +1151,14 @@ WaitEventAdjustPoll(WaitEventSet *set, WaitEvent *event)
 	{
 		pollfd->events = POLLIN;
 	}
+	else if (event->events == 0)
+	{
+		/*
+		 * If we're suppressing all socket events, remove the file descriptor
+		 * so poll() ignores this entry.
+		 */
+		pollfd->fd = -1;
+	}
 	else
 	{
 		Assert(event->events & (WL_SOCKET_READABLE |
@@ -1233,11 +1243,6 @@ WaitEventAdjustKqueue(WaitEventSet *set, WaitEvent *event, int old_events)
 		return;
 
 	Assert(event->events != WL_LATCH_SET || set->latch != NULL);
-	Assert(event->events == WL_LATCH_SET ||
-		   event->events == WL_POSTMASTER_DEATH ||
-		   (event->events & (WL_SOCKET_READABLE |
-							 WL_SOCKET_WRITEABLE |
-							 WL_SOCKET_CLOSED)));
 
 	if (event->events == WL_POSTMASTER_DEATH)
 	{
@@ -1340,7 +1345,14 @@ WaitEventAdjustWin32(WaitEventSet *set, WaitEvent *event)
 	}
 	else
 	{
-		int			flags = FD_CLOSE;	/* always check for errors/EOF */
+		int			flags = 0;
+
+		/*
+		 * Check for errors/EOF unless we're completely suppressing all events
+		 * for this socket.
+		 */
+		if (event->events != 0)
+			flags = FD_CLOSE;
 
 		if (event->events & WL_SOCKET_READABLE)
 			flags |= FD_READ;
-- 
2.30.2

