From db7a1ad2a7857e5b7a3aa679a0769fdc787ba4a1 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Fri, 10 Mar 2023 17:05:03 +1300
Subject: [PATCH 4/4] Provide fallback implementation of vacuum_cost_delay.

Since some systems don't have support for microsends in the underlying
kernel primitives used by the WaitEventSet API, but we also don't want
to give up postmaster death detection that commit 4753ef37e0ed added, we
need another way forward.  On such systems, re-introduce the pg_usleep()
call, but borrow commit 57dcc2ef's approach: poll for postmaster death
from time to time.

XXX Can we make WaitEventSetHasMicrosecondResolution() into a
compile-time constant?
---
 src/backend/commands/vacuum.c   | 31 ++++++++++++++++++++++++++-----
 src/backend/storage/ipc/latch.c | 15 +++++++++++++++
 src/include/storage/latch.h     |  1 +
 3 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index f379e60dca..98fc554152 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -50,6 +50,7 @@
 #include "postmaster/bgworker_internals.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
+#include "storage/pmsignal.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/acl.h"
@@ -2232,11 +2233,31 @@ vacuum_delay_point(void)
 		if (msec > VacuumCostDelay * 4)
 			msec = VacuumCostDelay * 4;
 
-		(void) WaitLatchUs(MyLatch,
-						   WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
-						   msec * 1000,
-						   WAIT_EVENT_VACUUM_DELAY);
-		ResetLatch(MyLatch);
+		if (!WaitEventSetHasMicrosecondResolution())
+		{
+			static uint32 postmaster_poll_count = 0;
+
+			/*
+			 * We need to use a plain old sleep to get microsecond resolution
+			 * on this platform, but we don't want to ignore postmaster death
+			 * during very long vacuums.  Checking involves a system call on
+			 * some systems, so check less frequently.
+			 */
+			if (postmaster_poll_count++ % 1024 == 0 && !PostmasterIsAlive())
+				exit(1);
+
+			pgstat_report_wait_start(WAIT_EVENT_VACUUM_DELAY);
+			pg_usleep(msec * 1000);
+			pgstat_report_wait_end();
+		}
+		else
+		{
+			(void) WaitLatchUs(MyLatch,
+							   WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+							   msec * 1000,
+							   WAIT_EVENT_VACUUM_DELAY);
+			ResetLatch(MyLatch);
+		}
 
 		VacuumCostBalance = 0;
 
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index 5c138ab9bf..5b590be9bf 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -2221,6 +2221,21 @@ WaitEventSetCanReportClosed(void)
 #endif
 }
 
+/*
+ * Return whether the current build options can ask the OS to wait with
+ * microsecond resolution.
+ */
+bool
+WaitEventSetHasMicrosecondResolution(void)
+{
+#if	defined(WAIT_USE_KQUEUE) || \
+	(defined(WAIT_USE_EPOLL) && defined(HAVE_EPOLL_PWAIT2))
+	return true;
+#else
+	return false;
+#endif
+}
+
 /*
  * Get the number of wait events registered in a given WaitEventSet.
  */
diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h
index 756c3114ed..27dc2dec3d 100644
--- a/src/include/storage/latch.h
+++ b/src/include/storage/latch.h
@@ -197,5 +197,6 @@ extern int	WaitLatchOrSocketUs(Latch *latch, int wakeEvents,
 extern void InitializeLatchWaitSet(void);
 extern int	GetNumRegisteredWaitEvents(WaitEventSet *set);
 extern bool WaitEventSetCanReportClosed(void);
+extern bool WaitEventSetHasMicrosecondResolution(void);
 
 #endif							/* LATCH_H */
-- 
2.39.2

