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 ConditionVariableCancelSleep().
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 ready to
receive it.

Author: Thomas Munro
Reviewed-by: Shawn Debnath
Discussion: https://postgr.es/m/CA%2BhUKGLQ_RW%2BXs8znDn36e-%2Bmq2--zrPemBqTQ8eKT-VO1OF4Q%40mail.gmail.com
This commit is contained in:
Thomas Munro 2019-07-13 13:55:10 +12:00
parent 1321509fa4
commit b91dd9de5e
1 changed files with 11 additions and 0 deletions

View File

@ -245,6 +245,7 @@ void
ConditionVariableCancelSleep(void)
{
ConditionVariable *cv = cv_sleep_target;
bool signaled = false;
if (cv == NULL)
return;
@ -252,8 +253,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;
}