From 0044078a540fcb2b5f5c728dcb7e4911b000d6d5 Mon Sep 17 00:00:00 2001 From: Bertrand Drouvot 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