@@ -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