Condition variable live lock
Thomas Munro <thomas.munro@enterprisedb.com>
From: Thomas Munro <thomas.munro@enterprisedb.com>
To: Pg Hackers <pgsql-hackers@postgresql.org>
Date: 2017-12-22T03:46:21Z
Lists: pgsql-hackers
Hi hackers,
While debugging a build farm assertion failure after commit 18042840,
and with the assumption that the problem is timing/scheduling
sensitive, I tried hammering the problem workload on a few different
machines and noticed that my slow 2-core test machine fairly regularly
got into a live lock state for tens to millions of milliseconds at a
time when there were 3+ active processes, in here:
int
ConditionVariableBroadcast(ConditionVariable *cv)
{
int nwoken = 0;
/*
* Let's just do this the dumbest way possible. We could try to dequeue
* all the sleepers at once to save spinlock cycles, but it's a bit hard
* to get that right in the face of possible sleep cancelations, and we
* don't want to loop holding the mutex.
*/
while (ConditionVariableSignal(cv))
++nwoken;
return nwoken;
}
The problem is that another backend can be woken up, determine that it
would like to wait for the condition variable again, and then get
itself added to the back of the wait queue *before the above loop has
finished*, so this interprocess ping-pong isn't guaranteed to
terminate. It seems that we'll need something slightly smarter than
the above to avoid that.
I don't currently suspect this phenomenon of being responsible for the
problem I'm hunting, even though it occurs on the only machine I've
been able to reproduce my real problem on. AFAICT the problem
described in this email should deliver arbitrary numbers of spurious
wake-ups wasting arbitrary CPU time but cause no harm that would
affect program correctness. So I didn't try to write a patch to fix
that just yet. I think we should probably back patch a fix when we
have one though, because it could bite Parallel Index Scan in
REL_10_STABLE.
--
Thomas Munro
http://www.enterprisedb.com
Commits
-
Add WL_EXIT_ON_PM_DEATH pseudo-event.
- cfdf4dc4fc96 12.0 landed
-
While waiting for a condition variable, detect postmaster death.
- 80259d4dbf47 11.0 landed
- d56a5f994c21 10.2 landed
-
Fix race condition during replication origin drop.
- 8a906204aec4 11.0 landed
- 1f5adbd799cf 10.2 landed
-
Allow ConditionVariable[PrepareTo]Sleep to auto-switch between CVs.
- 4af2190eb04b 10.2 landed
- 13db3b936359 11.0 landed
-
Cosmetic improvements in condition_variable.[hc].
- e35dba475a44 11.0 landed
-
Improve error detection capability in proclists.
- ea8e1bbc5384 11.0 landed
-
Remove return values of ConditionVariableSignal/Broadcast.
- ccf312a4488a 11.0 landed
-
Reorder steps in ConditionVariablePrepareToSleep for more safety.
- 83fe2708d668 10.2 landed
- 3cac0ec85992 11.0 landed
-
Rewrite ConditionVariableBroadcast() to avoid live-lock.
- aced5a92bf46 11.0 landed
- 1c77e990833a 10.2 landed
-
Add parallel-aware hash joins.
- 1804284042e6 11.0 cited