summaryrefslogtreecommitdiff
path: root/Python/ceval_gil.h
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2009-11-11 18:11:36 +0000
committerAntoine Pitrou <solipsis@pitrou.net>2009-11-11 18:11:36 +0000
commitcf4cabbe2a467cc0b17e69c10fbc0945acdb1706 (patch)
treede50494ba65b4a9fcd1e6c37f3cdb8fec54f2839 /Python/ceval_gil.h
parente29cd162edb5ed09caf265a4dfa5aceb04b9c957 (diff)
downloadcpython-git-cf4cabbe2a467cc0b17e69c10fbc0945acdb1706.tar.gz
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.
Diffstat (limited to 'Python/ceval_gil.h')
-rw-r--r--Python/ceval_gil.h33
1 files changed, 24 insertions, 9 deletions
diff --git a/Python/ceval_gil.h b/Python/ceval_gil.h
index 2687f9524d..bcc4fb9f6c 100644
--- a/Python/ceval_gil.h
+++ b/Python/ceval_gil.h
@@ -153,8 +153,20 @@ do { \
Py_FatalError("ReleaseMutex(" #mut ") failed"); };
/* We emulate condition variables with events. It is sufficient here.
- (WaitForMultipleObjects() allows the event to be caught and the mutex
- to be taken atomically) */
+ WaitForMultipleObjects() allows the event to be caught and the mutex
+ to be taken atomically.
+ As for SignalObjectAndWait(), its semantics are unfortunately a bit
+ more foggy. Many sources on the Web define it as atomically releasing
+ the first object while starting to wait on the second, but MSDN states
+ it is *not* atomic...
+
+ In any case, the emulation here is tailored for our particular use case.
+ For example, we don't care how many threads are woken up when a condition
+ gets signalled. Generic emulations of the pthread_cond_* API using
+ Win32 functions can be found on the Web.
+ The following read can be edificating (or not):
+ http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
+*/
#define COND_T HANDLE
#define COND_INIT(cond) \
/* auto-reset, non-signalled */ \
@@ -168,12 +180,9 @@ do { \
Py_FatalError("SetEvent(" #cond ") failed"); };
#define COND_WAIT(cond, mut) \
{ \
- DWORD r; \
- HANDLE objects[2] = { cond, mut }; \
- MUTEX_UNLOCK(mut); \
- r = WaitForMultipleObjects(2, objects, TRUE, INFINITE); \
- if (r != WAIT_OBJECT_0) \
- Py_FatalError("WaitForSingleObject(" #cond ") failed"); \
+ if (SignalObjectAndWait(mut, cond, INFINITE, FALSE) != WAIT_OBJECT_0) \
+ Py_FatalError("SignalObjectAndWait(" #mut ", " #cond") failed"); \
+ MUTEX_LOCK(mut); \
}
#define COND_TIMED_WAIT(cond, mut, microseconds, timeout_result) \
{ \
@@ -257,7 +266,8 @@ static void drop_gil(PyThreadState *tstate)
gil_locked = 0;
COND_SIGNAL(gil_cond);
#ifdef FORCE_SWITCHING
- COND_PREPARE(switch_cond);
+ if (gil_drop_request)
+ COND_PREPARE(switch_cond);
#endif
MUTEX_UNLOCK(gil_mutex);
@@ -266,6 +276,11 @@ static void drop_gil(PyThreadState *tstate)
MUTEX_LOCK(switch_mutex);
/* Not switched yet => wait */
if (gil_last_holder == tstate)
+ /* NOTE: if COND_WAIT does not atomically start waiting when
+ releasing the mutex, another thread can run through, take
+ the GIL and drop it again, and reset the condition
+ (COND_PREPARE above) before we even had a chance to wait
+ for it. */
COND_WAIT(switch_cond, switch_mutex);
MUTEX_UNLOCK(switch_mutex);
}