From 327fe5536a508963a68e8aded6dbb83effd68933 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Tue, 9 Jul 2019 20:48:06 +1200
Subject: [PATCH 2/3] Forward received condition variable signals on cancel.

After a process decides not to wait for a condition variable, it can
still consume a signal before it reaches ConditionVariableSleep().  In
that case, pass the signal on to another waiter if possible, so that
a signal doesn't go missing when there is another process waiting that
should receive it.

Author: Thomas Munro
Discussion: https://postgr.es/m/CA%2BhUKGLQ_RW%2BXs8znDn36e-%2Bmq2--zrPemBqTQ8eKT-VO1OF4Q%40mail.gmail.com
---
 src/backend/storage/lmgr/condition_variable.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index 951039da551..c22522beeb8 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -246,6 +246,7 @@ void
 ConditionVariableCancelSleep(void)
 {
 	ConditionVariable *cv = cv_sleep_target;
+	bool		signaled = false;
 
 	if (cv == NULL)
 		return;
@@ -253,8 +254,18 @@ ConditionVariableCancelSleep(void)
 	SpinLockAcquire(&cv->mutex);
 	if (proclist_contains(&cv->wakeup, MyProc->pgprocno, cvWaitLink))
 		proclist_delete(&cv->wakeup, MyProc->pgprocno, cvWaitLink);
+	else
+		signaled = true;
 	SpinLockRelease(&cv->mutex);
 
+	/*
+	 * If we've received a signal, pass it on to another waiting process, if
+	 * there is one.  Otherwise a call to ConditionVariableSignal() might get
+	 * lost, despite there being another process ready to handle it.
+	 */
+	if (signaled)
+		ConditionVariableSignal(cv);
+
 	cv_sleep_target = NULL;
 }
 
-- 
2.21.0

