Skip to content

Commit

Permalink
Issue python#15038:
Browse files Browse the repository at this point in the history
Fix incorrect test of the condition variable state, spotted by
Richard Oudkerk.  This could cause the internal condition variable
to grow without bounds.
  • Loading branch information
kristjanvalur committed Jun 19, 2012
1 parent 0d0a1de commit 1617077
Showing 1 changed file with 13 additions and 5 deletions.
18 changes: 13 additions & 5 deletions Python/condvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ PyMUTEX_UNLOCK(PyMUTEX_T *cs)
typedef struct _PyCOND_T
{
HANDLE sem;
int waiting;
int waiting; /* to allow PyCOND_SIGNAL to be a no-op */
} PyCOND_T;

Py_LOCAL_INLINE(int)
Expand Down Expand Up @@ -222,6 +222,10 @@ _PyCOND_WAIT_MS(PyCOND_T *cv, PyMUTEX_T *cs, DWORD ms)
* PyCOND_SIGNAL also decrements this value
* and signals releases the mutex. This is benign because it
* just means an extra spurious wakeup for a waiting thread.
* ('waiting' corresponds to the semaphore's "negative" count and
* we may end up with e.g. (waiting == -1 && sem.count == 1). When
* a new thread comes along, it will pass right throuhgh, having
* adjusted it to (waiting == 0 && sem.count == 0).
*/

if (wait == WAIT_FAILED)
Expand All @@ -246,10 +250,14 @@ PyCOND_TIMEDWAIT(PyCOND_T *cv, PyMUTEX_T *cs, long us)
Py_LOCAL_INLINE(int)
PyCOND_SIGNAL(PyCOND_T *cv)
{
if (cv->waiting) {
/* this test allows PyCOND_SIGNAL to be a no-op unless required
* to wake someone up, thus preventing an unbounded increase of
* the semaphore's internal counter.
*/
if (cv->waiting > 0) {
/* notifying thread decreases the cv->waiting count so that
* a delay between notify and wakeup doesn't cause a number
* of extra ReleaseSemaphore calls
* a delay between notify and actual wakeup of the target thread
* doesn't cause a number of extra ReleaseSemaphore calls.
*/
cv->waiting--;
return ReleaseSemaphore(cv->sem, 1, NULL) ? 0 : -1;
Expand All @@ -260,7 +268,7 @@ PyCOND_SIGNAL(PyCOND_T *cv)
Py_LOCAL_INLINE(int)
PyCOND_BROADCAST(PyCOND_T *cv)
{
if (cv->waiting) {
if (cv->waiting > 0) {
return ReleaseSemaphore(cv->sem, cv->waiting, NULL) ? 0 : -1;
cv->waiting = 0;
}
Expand Down

0 comments on commit 1617077

Please sign in to comment.