@@ -235,7 +235,31 @@ PyEval_GetCallStats(PyObject *self)
235
235
#endif
236
236
#include "pythread.h"
237
237
238
- static PyThread_type_lock interpreter_lock = 0 ; /* This is the GIL */
238
+ typedef void * PySpecial_cond_type ;
239
+
240
+ struct special_linkstruct {
241
+ PySpecial_cond_type wait ;
242
+ struct special_linkstruct * queue_next , * free_next ;
243
+ int in_use ;
244
+ };
245
+
246
+ typedef void * PySpecial_lock_type ;
247
+
248
+ typedef struct {
249
+ PySpecial_lock_type the_lock ;
250
+ struct special_linkstruct * wait_queue , * wait_last , * free_queue ;
251
+ } PySpecialSemaphore ;
252
+
253
+ void
254
+ PySpecial_init (PySpecialSemaphore * s )
255
+ {
256
+ s -> the_lock = PyThread_mutex_alloc ();
257
+ s -> wait_queue = NULL ;
258
+ s -> wait_last = NULL ;
259
+ s -> free_queue = NULL ;
260
+ }
261
+
262
+ static PySpecialSemaphore * interpreter_lock = NULL ; /* This is the GIL */
239
263
static PyThread_type_lock pending_lock = 0 ; /* for pending calls */
240
264
static long main_thread = 0 ;
241
265
@@ -245,26 +269,100 @@ PyEval_ThreadsInitialized(void)
245
269
return interpreter_lock != 0 ;
246
270
}
247
271
272
+ static PySpecialSemaphore * allocate_special (void )
273
+ {
274
+ PySpecialSemaphore * s = malloc (sizeof (PySpecialSemaphore ));
275
+ PySpecial_init (s );
276
+ return s ;
277
+ }
278
+
279
+ static struct special_linkstruct * allocate_special_linkstruct (void )
280
+ {
281
+ struct special_linkstruct * ls = malloc (sizeof (struct special_linkstruct ));
282
+ ls -> wait = PyThread_cond_alloc ();
283
+ ls -> queue_next = NULL ;
284
+ ls -> free_next = NULL ;
285
+ ls -> in_use = 0 ;
286
+ return ls ;
287
+ }
288
+
289
+ static void PySpecial_Lock (PySpecialSemaphore * s )
290
+ {
291
+ struct special_linkstruct * ls ;
292
+
293
+ PyThread_mutex_lock (s -> the_lock );
294
+
295
+ if (!s -> free_queue )
296
+ s -> free_queue = allocate_special_linkstruct ();
297
+
298
+ ls = s -> free_queue ;
299
+ s -> free_queue = ls -> free_next ;
300
+
301
+ if (!s -> wait_queue )
302
+ {
303
+ ls -> in_use = 1 ;
304
+ s -> wait_queue = ls ;
305
+ s -> wait_last = ls ;
306
+ PyThread_mutex_unlock (s -> the_lock );
307
+ return ;
308
+ }
309
+
310
+ assert (s -> wait_queue != ls );
311
+ assert (s -> wait_last != ls );
312
+ assert (s -> wait_last -> queue_next == NULL );
313
+ assert (!ls -> in_use );
314
+ s -> wait_last -> queue_next = ls ;
315
+ s -> wait_last = ls ;
316
+ ls -> in_use = 1 ;
317
+
318
+ while (s -> wait_queue != ls )
319
+ PyThread_cond_wait (ls -> wait , s -> the_lock );
320
+
321
+ PyThread_mutex_unlock (s -> the_lock );
322
+ }
323
+
324
+ static void PySpecial_Unlock (PySpecialSemaphore * s )
325
+ {
326
+ struct special_linkstruct * ls ;
327
+
328
+ PyThread_mutex_lock (s -> the_lock );
329
+ ls = s -> wait_queue ;
330
+ assert (ls -> in_use );
331
+
332
+ s -> wait_queue = ls -> queue_next ;
333
+ if (s -> wait_queue )
334
+ {
335
+ ls -> queue_next = NULL ;
336
+ PyThread_cond_signal (s -> wait_queue -> wait );
337
+ }
338
+ ls -> in_use = 0 ;
339
+
340
+ ls -> free_next = s -> free_queue ;
341
+ s -> free_queue = ls ;
342
+
343
+ PyThread_mutex_unlock (s -> the_lock );
344
+ }
345
+
248
346
void
249
347
PyEval_InitThreads (void )
250
348
{
251
349
if (interpreter_lock )
252
350
return ;
253
- interpreter_lock = PyThread_allocate_lock ();
254
- PyThread_acquire_lock (interpreter_lock , 1 );
351
+ interpreter_lock = allocate_special ();
352
+ PySpecial_Lock (interpreter_lock );
255
353
main_thread = PyThread_get_thread_ident ();
256
354
}
257
355
258
356
void
259
357
PyEval_AcquireLock (void )
260
358
{
261
- PyThread_acquire_lock (interpreter_lock , 1 );
359
+ PySpecial_Lock (interpreter_lock );
262
360
}
263
361
264
362
void
265
363
PyEval_ReleaseLock (void )
266
364
{
267
- PyThread_release_lock (interpreter_lock );
365
+ PySpecial_Unlock (interpreter_lock );
268
366
}
269
367
270
368
void
@@ -274,7 +372,7 @@ PyEval_AcquireThread(PyThreadState *tstate)
274
372
Py_FatalError ("PyEval_AcquireThread: NULL new thread state" );
275
373
/* Check someone has called PyEval_InitThreads() to create the lock */
276
374
assert (interpreter_lock );
277
- PyThread_acquire_lock (interpreter_lock , 1 );
375
+ PySpecial_Lock (interpreter_lock );
278
376
if (PyThreadState_Swap (tstate ) != NULL )
279
377
Py_FatalError (
280
378
"PyEval_AcquireThread: non-NULL old thread state" );
@@ -287,7 +385,7 @@ PyEval_ReleaseThread(PyThreadState *tstate)
287
385
Py_FatalError ("PyEval_ReleaseThread: NULL thread state" );
288
386
if (PyThreadState_Swap (NULL ) != tstate )
289
387
Py_FatalError ("PyEval_ReleaseThread: wrong thread state" );
290
- PyThread_release_lock (interpreter_lock );
388
+ PySpecial_Unlock (interpreter_lock );
291
389
}
292
390
293
391
/* This function is called from PyOS_AfterFork to ensure that newly
@@ -307,9 +405,9 @@ PyEval_ReInitThreads(void)
307
405
much error-checking. Doing this cleanly would require
308
406
adding a new function to each thread_*.h. Instead, just
309
407
create a new lock and waste a little bit of memory */
310
- interpreter_lock = PyThread_allocate_lock ();
408
+ interpreter_lock = allocate_special ();
311
409
pending_lock = PyThread_allocate_lock ();
312
- PyThread_acquire_lock (interpreter_lock , 1 );
410
+ PySpecial_Lock (interpreter_lock );
313
411
main_thread = PyThread_get_thread_ident ();
314
412
315
413
/* Update the threading module with the new state.
@@ -343,7 +441,7 @@ PyEval_SaveThread(void)
343
441
Py_FatalError ("PyEval_SaveThread: NULL tstate" );
344
442
#ifdef WITH_THREAD
345
443
if (interpreter_lock )
346
- PyThread_release_lock (interpreter_lock );
444
+ PySpecial_Unlock (interpreter_lock );
347
445
#endif
348
446
return tstate ;
349
447
}
@@ -356,7 +454,7 @@ PyEval_RestoreThread(PyThreadState *tstate)
356
454
#ifdef WITH_THREAD
357
455
if (interpreter_lock ) {
358
456
int err = errno ;
359
- PyThread_acquire_lock (interpreter_lock , 1 );
457
+ PySpecial_Lock (interpreter_lock );
360
458
errno = err ;
361
459
}
362
460
#endif
@@ -1119,20 +1217,23 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
1119
1217
_Py_Ticker = 0 ;
1120
1218
}
1121
1219
#ifdef WITH_THREAD
1122
- if (interpreter_lock ) {
1220
+ if (interpreter_lock && interpreter_lock -> wait_queue ) {
1123
1221
/* Give another thread a chance */
1124
1222
1125
1223
if (PyThreadState_Swap (NULL ) != tstate )
1126
1224
Py_FatalError ("ceval: tstate mix-up" );
1127
- PyThread_release_lock (interpreter_lock );
1225
+ PySpecial_Unlock (interpreter_lock );
1128
1226
1129
1227
/* Other threads may run now */
1130
1228
1131
- PyThread_acquire_lock (interpreter_lock , 1 );
1229
+ PySpecial_Lock (interpreter_lock );
1132
1230
1133
1231
if (PyThreadState_Swap (tstate ) != NULL )
1134
1232
Py_FatalError ("ceval: orphan tstate" );
1135
1233
1234
+ }
1235
+
1236
+ if (interpreter_lock ) {
1136
1237
/* Check for thread interrupts */
1137
1238
1138
1239
if (tstate -> async_exc != NULL ) {
0 commit comments