v2-0001-Introduce-ConditionVariableEventSleep.txt

text/plain

Filename: v2-0001-Introduce-ConditionVariableEventSleep.txt
Type: text/plain
Part: 1
Message: Re: Minimal logical decoding on standbys
From 0044078a540fcb2b5f5c728dcb7e4911b000d6d5 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Fri, 10 Mar 2023 10:57:22 +0000
Subject: [PATCH v99 4/7] Introduce-ConditionVariableEventSleep

---
 src/backend/storage/lmgr/condition_variable.c | 65 ++++++++++++++-----
 src/include/storage/condition_variable.h      |  7 ++
 2 files changed, 57 insertions(+), 15 deletions(-)
  89.0% src/backend/storage/lmgr/
  10.9% src/include/storage/

diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index 7e2bbf46d9..af241e7317 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -97,7 +97,8 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
 void
 ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
 {
-	(void) ConditionVariableTimedSleep(cv, -1 /* no timeout */ ,
+	(void) ConditionVariableEventSleep(cv, NULL, NULL, NULL,
+									   -1 /* no timeout */ ,
 									   wait_event_info);
 }
 
@@ -111,11 +112,28 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
 bool
 ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
 							uint32 wait_event_info)
+{
+	return ConditionVariableEventSleep(cv, NULL, NULL, NULL, timeout,
+									   wait_event_info);
+}
+
+/*
+ * Wait for a condition variable to be signaled, a timeout to be reached, or a
+ * socket event in the given waitset.
+ *
+ * Returns true when timeout expires, otherwise returns false.
+ *
+ * See ConditionVariableSleep() for general usage.
+ */
+bool
+ConditionVariableEventSleep(ConditionVariable *cv, bool (*cv_resume_waiting)(void),
+							WaitEventSet *waitset,
+							bool (*waitset_resume_waiting)(void),
+							long timeout, uint32 wait_event_info)
 {
 	long		cur_timeout = -1;
 	instr_time	start_time;
 	instr_time	cur_time;
-	int			wait_events;
 
 	/*
 	 * If the caller didn't prepare to sleep explicitly, then do so now and
@@ -132,7 +150,7 @@ ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
 	 * If we are currently prepared to sleep on some other CV, we just cancel
 	 * that and prepare this one; see ConditionVariablePrepareToSleep.
 	 */
-	if (cv_sleep_target != cv)
+	if (cv && cv_sleep_target != cv)
 	{
 		ConditionVariablePrepareToSleep(cv);
 		return false;
@@ -147,24 +165,29 @@ ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
 		INSTR_TIME_SET_CURRENT(start_time);
 		Assert(timeout >= 0 && timeout <= INT_MAX);
 		cur_timeout = timeout;
-		wait_events = WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH;
 	}
-	else
-		wait_events = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH;
 
 	while (true)
 	{
 		bool		done = false;
+		WaitEvent	cvEvent;
+		int			nevents = 0;
 
 		/*
-		 * Wait for latch to be set.  (If we're awakened for some other
-		 * reason, the code below will cope anyway.)
+		 * Wait for latch to be set, or other events which will be handled
+		 * below.
 		 */
-		(void) WaitLatch(MyLatch, wait_events, cur_timeout, wait_event_info);
+		if (waitset)
+			nevents = WaitEventSetWait(waitset, cur_timeout, &cvEvent,
+									   1, wait_event_info);
 
 		/* Reset latch before examining the state of the wait list. */
 		ResetLatch(MyLatch);
 
+		/* If a socket event occurred, no need to check wait list. */
+		if (nevents == 1 && (cvEvent.events & WL_SOCKET_MASK) != 0)
+			return true;
+
 		/*
 		 * If this process has been taken out of the wait list, then we know
 		 * that it has been signaled by ConditionVariableSignal (or
@@ -180,13 +203,25 @@ ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
 		 * by something other than ConditionVariableSignal; though we don't
 		 * guarantee not to return spuriously, we'll avoid this obvious case.
 		 */
-		SpinLockAcquire(&cv->mutex);
-		if (!proclist_contains(&cv->wakeup, MyProc->pgprocno, cvWaitLink))
+
+		if (cv)
 		{
-			done = true;
-			proclist_push_tail(&cv->wakeup, MyProc->pgprocno, cvWaitLink);
+			SpinLockAcquire(&cv->mutex);
+			if (!proclist_contains(&cv->wakeup, MyProc->pgprocno, cvWaitLink))
+			{
+				done = true;
+				proclist_push_tail(&cv->wakeup, MyProc->pgprocno, cvWaitLink);
+			}
+			SpinLockRelease(&cv->mutex);
 		}
-		SpinLockRelease(&cv->mutex);
+
+		/* If we are not waiting on a CV or don't want to wait anymore */
+		if (!cv || (cv && cv_resume_waiting && !cv_resume_waiting()))
+			done = true;
+
+		/* If we don't want to wait on the waitset anymore */
+		if (waitset && waitset_resume_waiting && !waitset_resume_waiting())
+			done = true;
 
 		/*
 		 * Check for interrupts, and return spuriously if that caused the
@@ -194,7 +229,7 @@ ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
 		 * waited for a different condition variable).
 		 */
 		CHECK_FOR_INTERRUPTS();
-		if (cv != cv_sleep_target)
+		if (cv && cv != cv_sleep_target)
 			done = true;
 
 		/* We were signaled, so return */
diff --git a/src/include/storage/condition_variable.h b/src/include/storage/condition_variable.h
index 589bdd323c..b9510caa17 100644
--- a/src/include/storage/condition_variable.h
+++ b/src/include/storage/condition_variable.h
@@ -22,6 +22,7 @@
 #ifndef CONDITION_VARIABLE_H
 #define CONDITION_VARIABLE_H
 
+#include "storage/latch.h"
 #include "storage/proclist_types.h"
 #include "storage/spin.h"
 
@@ -56,6 +57,12 @@ extern void ConditionVariableInit(ConditionVariable *cv);
 extern void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info);
 extern bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
 										uint32 wait_event_info);
+extern bool ConditionVariableEventSleep(ConditionVariable *cv,
+										bool (*cv_resume_waiting)(void),
+										WaitEventSet *cvEventSet,
+										bool (*waitset_resume_waiting)(void),
+										long timeout,
+										uint32 wait_event_info);
 extern void ConditionVariableCancelSleep(void);
 
 /*
-- 
2.34.1