@@ -59,213 +59,49 @@ static unsigned long gil_interval = DEFAULT_INTERVAL;
5959 (Note: this mechanism is enabled with FORCE_SWITCHING above)
6060*/
6161
62- #ifndef _POSIX_THREADS
63- /* This means pthreads are not implemented in libc headers, hence the macro
64- not present in unistd.h. But they still can be implemented as an external
65- library (e.g. gnu pth in pthread emulation) */
66- # ifdef HAVE_PTHREAD_H
67- # include <pthread.h> /* _POSIX_THREADS */
68- # endif
69- #endif
70-
71-
72- #ifdef _POSIX_THREADS
73-
74- /*
75- * POSIX support
76- */
77-
78- #include <pthread.h>
79-
80- #define ADD_MICROSECONDS (tv , interval ) \
81- do { \
82- tv.tv_usec += (long) interval; \
83- tv.tv_sec += tv.tv_usec / 1000000; \
84- tv.tv_usec %= 1000000; \
85- } while (0)
86-
87- /* We assume all modern POSIX systems have gettimeofday() */
88- #ifdef GETTIMEOFDAY_NO_TZ
89- #define GETTIMEOFDAY (ptv ) gettimeofday(ptv)
90- #else
91- #define GETTIMEOFDAY (ptv ) gettimeofday(ptv, (struct timezone *)NULL)
62+ #include "condvar.h"
63+ #ifndef Py_HAVE_CONDVAR
64+ #error You need either a POSIX-compatible or a Windows system!
9265#endif
9366
94- #define MUTEX_T pthread_mutex_t
67+ #define MUTEX_T PyMUTEX_T
9568#define MUTEX_INIT (mut ) \
96- if (pthread_mutex_init(& mut, NULL )) { \
97- Py_FatalError("pthread_mutex_init (" #mut ") failed"); };
69+ if (PyMUTEX_INIT(&( mut) )) { \
70+ Py_FatalError("PyMUTEX_INIT (" #mut ") failed"); };
9871#define MUTEX_FINI (mut ) \
99- if (pthread_mutex_destroy(& mut)) { \
100- Py_FatalError("pthread_mutex_destroy (" #mut ") failed"); };
72+ if (PyMUTEX_FINI(&( mut) )) { \
73+ Py_FatalError("PyMUTEX_FINI (" #mut ") failed"); };
10174#define MUTEX_LOCK (mut ) \
102- if (pthread_mutex_lock(& mut)) { \
103- Py_FatalError("pthread_mutex_lock (" #mut ") failed"); };
75+ if (PyMUTEX_LOCK(&( mut) )) { \
76+ Py_FatalError("PyMUTEX_LOCK (" #mut ") failed"); };
10477#define MUTEX_UNLOCK (mut ) \
105- if (pthread_mutex_unlock(& mut)) { \
106- Py_FatalError("pthread_mutex_unlock (" #mut ") failed"); };
78+ if (PyMUTEX_UNLOCK(&( mut) )) { \
79+ Py_FatalError("PyMUTEX_UNLOCK (" #mut ") failed"); };
10780
108- #define COND_T pthread_cond_t
81+ #define COND_T PyCOND_T
10982#define COND_INIT (cond ) \
110- if (pthread_cond_init(& cond, NULL )) { \
111- Py_FatalError("pthread_cond_init (" #cond ") failed"); };
83+ if (PyCOND_INIT(&( cond) )) { \
84+ Py_FatalError("PyCOND_INIT (" #cond ") failed"); };
11285#define COND_FINI (cond ) \
113- if (pthread_cond_destroy(& cond)) { \
114- Py_FatalError("pthread_cond_destroy (" #cond ") failed"); };
86+ if (PyCOND_FINI(&( cond) )) { \
87+ Py_FatalError("PyCOND_FINI (" #cond ") failed"); };
11588#define COND_SIGNAL (cond ) \
116- if (pthread_cond_signal(& cond)) { \
117- Py_FatalError("pthread_cond_signal (" #cond ") failed"); };
89+ if (PyCOND_SIGNAL(&( cond) )) { \
90+ Py_FatalError("PyCOND_SIGNAL (" #cond ") failed"); };
11891#define COND_WAIT (cond , mut ) \
119- if (pthread_cond_wait(& cond, &mut)) { \
120- Py_FatalError("pthread_cond_wait (" #cond ") failed"); };
92+ if (PyCOND_WAIT(&( cond) , &( mut) )) { \
93+ Py_FatalError("PyCOND_WAIT (" #cond ") failed"); };
12194#define COND_TIMED_WAIT (cond , mut , microseconds , timeout_result ) \
12295 { \
123- int r; \
124- struct timespec ts; \
125- struct timeval deadline; \
126- \
127- GETTIMEOFDAY(&deadline); \
128- ADD_MICROSECONDS(deadline, microseconds); \
129- ts.tv_sec = deadline.tv_sec; \
130- ts.tv_nsec = deadline.tv_usec * 1000; \
131- \
132- r = pthread_cond_timedwait(&cond, &mut, &ts); \
133- if (r == ETIMEDOUT) \
96+ int r = PyCOND_TIMEDWAIT(&(cond), &(mut), (microseconds)); \
97+ if (r < 0) \
98+ Py_FatalError("PyCOND_WAIT(" #cond ") failed"); \
99+ if (r) /* 1 == timeout, 2 == impl. can't say, so assume timeout */ \
134100 timeout_result = 1 ; \
135- else if (r) \
136- Py_FatalError("pthread_cond_timedwait(" #cond ") failed"); \
137101 else \
138102 timeout_result = 0 ; \
139103 } \
140104
141- #elif defined(NT_THREADS )
142-
143- /*
144- * Windows (2000 and later, as well as (hopefully) CE) support
145- */
146-
147- #include <windows.h>
148-
149- #define MUTEX_T CRITICAL_SECTION
150- #define MUTEX_INIT (mut ) do { \
151- if (!(InitializeCriticalSectionAndSpinCount(&(mut), 4000))) \
152- Py_FatalError("CreateMutex(" #mut ") failed"); \
153- } while (0)
154- #define MUTEX_FINI (mut ) \
155- DeleteCriticalSection(&(mut))
156- #define MUTEX_LOCK (mut ) \
157- EnterCriticalSection(&(mut))
158- #define MUTEX_UNLOCK (mut ) \
159- LeaveCriticalSection(&(mut))
160-
161- /* We emulate condition variables with a semaphore.
162- We use a Semaphore rather than an auto-reset event, because although
163- an auto-resent event might appear to solve the lost-wakeup bug (race
164- condition between releasing the outer lock and waiting) because it
165- maintains state even though a wait hasn't happened, there is still
166- a lost wakeup problem if more than one thread are interrupted in the
167- critical place. A semaphore solves that.
168- Because it is ok to signal a condition variable with no one
169- waiting, we need to keep track of the number of
170- waiting threads. Otherwise, the semaphore's state could rise
171- without bound.
172-
173- Generic emulations of the pthread_cond_* API using
174- Win32 functions can be found on the Web.
175- The following read can be edificating (or not):
176- http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
177- */
178- typedef struct COND_T
179- {
180- HANDLE sem ; /* the semaphore */
181- int n_waiting ; /* how many are unreleased */
182- } COND_T ;
183-
184- __inline static void _cond_init (COND_T * cond )
185- {
186- /* A semaphore with a large max value, The positive value
187- * is only needed to catch those "lost wakeup" events and
188- * race conditions when a timed wait elapses.
189- */
190- if (!(cond -> sem = CreateSemaphore (NULL , 0 , 1000 , NULL )))
191- Py_FatalError ("CreateSemaphore() failed" );
192- cond -> n_waiting = 0 ;
193- }
194-
195- __inline static void _cond_fini (COND_T * cond )
196- {
197- BOOL ok = CloseHandle (cond -> sem );
198- if (!ok )
199- Py_FatalError ("CloseHandle() failed" );
200- }
201-
202- __inline static void _cond_wait (COND_T * cond , MUTEX_T * mut )
203- {
204- ++ cond -> n_waiting ;
205- MUTEX_UNLOCK (* mut );
206- /* "lost wakeup bug" would occur if the caller were interrupted here,
207- * but we are safe because we are using a semaphore wich has an internal
208- * count.
209- */
210- if (WaitForSingleObject (cond -> sem , INFINITE ) == WAIT_FAILED )
211- Py_FatalError ("WaitForSingleObject() failed" );
212- MUTEX_LOCK (* mut );
213- }
214-
215- __inline static int _cond_timed_wait (COND_T * cond , MUTEX_T * mut ,
216- int us )
217- {
218- DWORD r ;
219- ++ cond -> n_waiting ;
220- MUTEX_UNLOCK (* mut );
221- r = WaitForSingleObject (cond -> sem , us / 1000 );
222- if (r == WAIT_FAILED )
223- Py_FatalError ("WaitForSingleObject() failed" );
224- MUTEX_LOCK (* mut );
225- if (r == WAIT_TIMEOUT )
226- -- cond -> n_waiting ;
227- /* Here we have a benign race condition with _cond_signal. If the
228- * wait operation has timed out, but before we can acquire the
229- * mutex again to decrement n_waiting, a thread holding the mutex
230- * still sees a positive n_waiting value and may call
231- * ReleaseSemaphore and decrement n_waiting.
232- * This will cause n_waiting to be decremented twice.
233- * This is benign, though, because ReleaseSemaphore will also have
234- * been called, leaving the semaphore state positive. We may
235- * thus end up with semaphore in state 1, and n_waiting == -1, and
236- * the next time someone calls _cond_wait(), that thread will
237- * pass right through, decrementing the semaphore state and
238- * incrementing n_waiting, thus correcting the extra _cond_signal.
239- */
240- return r == WAIT_TIMEOUT ;
241- }
242-
243- __inline static void _cond_signal (COND_T * cond ) {
244- /* NOTE: This must be called with the mutex held */
245- if (cond -> n_waiting > 0 ) {
246- if (!ReleaseSemaphore (cond -> sem , 1 , NULL ))
247- Py_FatalError ("ReleaseSemaphore() failed" );
248- -- cond -> n_waiting ;
249- }
250- }
251-
252- #define COND_INIT (cond ) \
253- _cond_init(&(cond))
254- #define COND_FINI (cond ) \
255- _cond_fini(&(cond))
256- #define COND_SIGNAL (cond ) \
257- _cond_signal(&(cond))
258- #define COND_WAIT (cond , mut ) \
259- _cond_wait(&(cond), &(mut))
260- #define COND_TIMED_WAIT (cond , mut , us , timeout_result ) do { \
261- (timeout_result) = _cond_timed_wait(&(cond), &(mut), us); \
262- } while (0)
263-
264- #else
265-
266- #error You need either a POSIX-compatible or a Windows system!
267-
268- #endif /* _POSIX_THREADS, NT_THREADS */
269105
270106
271107/* Whether the GIL is already taken (-1 if uninitialized). This is atomic
@@ -356,13 +192,13 @@ static void drop_gil(PyThreadState *tstate)
356192 MUTEX_LOCK (switch_mutex );
357193 /* Not switched yet => wait */
358194 if (_Py_atomic_load_relaxed (& gil_last_holder ) == tstate ) {
359- RESET_GIL_DROP_REQUEST ();
195+ RESET_GIL_DROP_REQUEST ();
360196 /* NOTE: if COND_WAIT does not atomically start waiting when
361197 releasing the mutex, another thread can run through, take
362198 the GIL and drop it again, and reset the condition
363199 before we even had a chance to wait for it. */
364200 COND_WAIT (switch_cond , switch_mutex );
365- }
201+ }
366202 MUTEX_UNLOCK (switch_mutex );
367203 }
368204#endif
0 commit comments