Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cf4cabb

Browse files
committed
Our condition variable emulation under Windows is imperfect, which
seems to be the cause of the buildbot hangs. Try to fix it, and add some comments.
1 parent e29cd16 commit cf4cabb

1 file changed

Lines changed: 24 additions & 9 deletions

File tree

Python/ceval_gil.h

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,20 @@ do { \
153153
Py_FatalError("ReleaseMutex(" #mut ") failed"); };
154154

155155
/* We emulate condition variables with events. It is sufficient here.
156-
(WaitForMultipleObjects() allows the event to be caught and the mutex
157-
to be taken atomically) */
156+
WaitForMultipleObjects() allows the event to be caught and the mutex
157+
to be taken atomically.
158+
As for SignalObjectAndWait(), its semantics are unfortunately a bit
159+
more foggy. Many sources on the Web define it as atomically releasing
160+
the first object while starting to wait on the second, but MSDN states
161+
it is *not* atomic...
162+
163+
In any case, the emulation here is tailored for our particular use case.
164+
For example, we don't care how many threads are woken up when a condition
165+
gets signalled. Generic emulations of the pthread_cond_* API using
166+
Win32 functions can be found on the Web.
167+
The following read can be edificating (or not):
168+
http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
169+
*/
158170
#define COND_T HANDLE
159171
#define COND_INIT(cond) \
160172
/* auto-reset, non-signalled */ \
@@ -168,12 +180,9 @@ do { \
168180
Py_FatalError("SetEvent(" #cond ") failed"); };
169181
#define COND_WAIT(cond, mut) \
170182
{ \
171-
DWORD r; \
172-
HANDLE objects[2] = { cond, mut }; \
173-
MUTEX_UNLOCK(mut); \
174-
r = WaitForMultipleObjects(2, objects, TRUE, INFINITE); \
175-
if (r != WAIT_OBJECT_0) \
176-
Py_FatalError("WaitForSingleObject(" #cond ") failed"); \
183+
if (SignalObjectAndWait(mut, cond, INFINITE, FALSE) != WAIT_OBJECT_0) \
184+
Py_FatalError("SignalObjectAndWait(" #mut ", " #cond") failed"); \
185+
MUTEX_LOCK(mut); \
177186
}
178187
#define COND_TIMED_WAIT(cond, mut, microseconds, timeout_result) \
179188
{ \
@@ -257,7 +266,8 @@ static void drop_gil(PyThreadState *tstate)
257266
gil_locked = 0;
258267
COND_SIGNAL(gil_cond);
259268
#ifdef FORCE_SWITCHING
260-
COND_PREPARE(switch_cond);
269+
if (gil_drop_request)
270+
COND_PREPARE(switch_cond);
261271
#endif
262272
MUTEX_UNLOCK(gil_mutex);
263273

@@ -266,6 +276,11 @@ static void drop_gil(PyThreadState *tstate)
266276
MUTEX_LOCK(switch_mutex);
267277
/* Not switched yet => wait */
268278
if (gil_last_holder == tstate)
279+
/* NOTE: if COND_WAIT does not atomically start waiting when
280+
releasing the mutex, another thread can run through, take
281+
the GIL and drop it again, and reset the condition
282+
(COND_PREPARE above) before we even had a chance to wait
283+
for it. */
269284
COND_WAIT(switch_cond, switch_mutex);
270285
MUTEX_UNLOCK(switch_mutex);
271286
}

0 commit comments

Comments
 (0)