aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/storage/lmgr/condition_variable.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index 552bdaaf809..730adf1c57f 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -70,10 +70,15 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
}
/*
- * It's not legal to prepare a sleep until the previous sleep has been
- * completed or canceled.
+ * If some other sleep is already prepared, cancel it; this is necessary
+ * because we have just one static variable tracking the prepared sleep,
+ * and also only one cvWaitLink in our PGPROC. It's okay to do this
+ * because whenever control does return to the other test-and-sleep loop,
+ * its ConditionVariableSleep call will just re-establish that sleep as
+ * the prepared one.
*/
- Assert(cv_sleep_target == NULL);
+ if (cv_sleep_target != NULL)
+ ConditionVariableCancelSleep();
/* Record the condition variable on which we will sleep. */
cv_sleep_target = cv;
@@ -121,16 +126,16 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
* allows you to skip manipulation of the wait list, or not met initially,
* in which case preparing first allows you to skip a spurious test of the
* caller's exit condition.
+ *
+ * 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 == NULL)
+ if (cv_sleep_target != cv)
{
ConditionVariablePrepareToSleep(cv);
return;
}
- /* Any earlier condition variable sleep must have been canceled. */
- Assert(cv_sleep_target == cv);
-
while (!done)
{
CHECK_FOR_INTERRUPTS();
@@ -246,7 +251,8 @@ ConditionVariableBroadcast(ConditionVariable *cv)
* prepared CV sleep. The next call to ConditionVariableSleep will take
* care of re-establishing the lost state.
*/
- ConditionVariableCancelSleep();
+ if (cv_sleep_target != NULL)
+ ConditionVariableCancelSleep();
/*
* Inspect the state of the queue. If it's empty, we have nothing to do.