@@ -174,9 +174,11 @@ PyEval_InitThreads(void)
174174 PyThread_init_thread ();
175175 create_gil ();
176176 take_gil (_PyThreadState_GET ());
177- _PyRuntime .ceval .pending .main_thread = PyThread_get_thread_ident ();
178- if (!_PyRuntime .ceval .pending .lock )
177+ // Set it to the ID of the main thread of the main interpreter.
178+ _PyRuntime .main_thread = PyThread_get_thread_ident ();
179+ if (!_PyRuntime .ceval .pending .lock ) {
179180 _PyRuntime .ceval .pending .lock = PyThread_allocate_lock ();
181+ }
180182}
181183
182184void
@@ -243,9 +245,9 @@ PyEval_ReInitThreads(void)
243245 if (!gil_created ())
244246 return ;
245247 recreate_gil ();
246- _PyRuntime .ceval .pending .lock = PyThread_allocate_lock ();
247248 take_gil (current_tstate );
248- _PyRuntime .ceval .pending .main_thread = PyThread_get_thread_ident ();
249+ _PyRuntime .main_thread = PyThread_get_thread_ident ();
250+ _PyRuntime .ceval .pending .lock = PyThread_allocate_lock ();
249251
250252 /* Destroy all threads except the current one */
251253 _PyThreadState_DeleteExcept (current_tstate );
@@ -323,6 +325,35 @@ _PyEval_SignalReceived(void)
323325 SIGNAL_PENDING_SIGNALS ();
324326}
325327
328+ /* Push one item onto the queue while holding the lock. */
329+ static int
330+ _push_pending_call (int (* func )(void * ), void * arg )
331+ {
332+ int i = _PyRuntime .ceval .pending .last ;
333+ int j = (i + 1 ) % NPENDINGCALLS ;
334+ if (j == _PyRuntime .ceval .pending .first ) {
335+ return -1 ; /* Queue full */
336+ }
337+ _PyRuntime .ceval .pending .calls [i ].func = func ;
338+ _PyRuntime .ceval .pending .calls [i ].arg = arg ;
339+ _PyRuntime .ceval .pending .last = j ;
340+ return 0 ;
341+ }
342+
343+ /* Pop one item off the queue while holding the lock. */
344+ static void
345+ _pop_pending_call (int (* * func )(void * ), void * * arg )
346+ {
347+ int i = _PyRuntime .ceval .pending .first ;
348+ if (i == _PyRuntime .ceval .pending .last ) {
349+ return ; /* Queue empty */
350+ }
351+
352+ * func = _PyRuntime .ceval .pending .calls [i ].func ;
353+ * arg = _PyRuntime .ceval .pending .calls [i ].arg ;
354+ _PyRuntime .ceval .pending .first = (i + 1 ) % NPENDINGCALLS ;
355+ }
356+
326357/* This implementation is thread-safe. It allows
327358 scheduling to be made from any thread, and even from an executing
328359 callback.
@@ -331,7 +362,6 @@ _PyEval_SignalReceived(void)
331362int
332363Py_AddPendingCall (int (* func )(void * ), void * arg )
333364{
334- int i , j , result = 0 ;
335365 PyThread_type_lock lock = _PyRuntime .ceval .pending .lock ;
336366
337367 /* try a few times for the lock. Since this mechanism is used
@@ -346,6 +376,7 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
346376 * this function is called before any bytecode evaluation takes place.
347377 */
348378 if (lock != NULL ) {
379+ int i ;
349380 for (i = 0 ; i < 100 ; i ++ ) {
350381 if (PyThread_acquire_lock (lock , NOWAIT_LOCK ))
351382 break ;
@@ -354,15 +385,8 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
354385 return -1 ;
355386 }
356387
357- i = _PyRuntime .ceval .pending .last ;
358- j = (i + 1 ) % NPENDINGCALLS ;
359- if (j == _PyRuntime .ceval .pending .first ) {
360- result = -1 ; /* Queue full */
361- } else {
362- _PyRuntime .ceval .pending .calls [i ].func = func ;
363- _PyRuntime .ceval .pending .calls [i ].arg = arg ;
364- _PyRuntime .ceval .pending .last = j ;
365- }
388+ int result = _push_pending_call (func , arg );
389+
366390 /* signal main loop */
367391 SIGNAL_PENDING_CALLS ();
368392 if (lock != NULL )
@@ -373,10 +397,10 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
373397static int
374398handle_signals (void )
375399{
376- /* Only handle signals on main thread. */
377- if ( _PyRuntime . ceval . pending . main_thread &&
378- PyThread_get_thread_ident () != _PyRuntime . ceval . pending . main_thread )
379- {
400+ /* Only handle signals on main thread. PyEval_InitThreads must
401+ * have been called already.
402+ */
403+ if ( PyThread_get_thread_ident () != _PyRuntime . main_thread ) {
380404 return 0 ;
381405 }
382406 /*
@@ -401,9 +425,7 @@ make_pending_calls(void)
401425 static int busy = 0 ;
402426
403427 /* only service pending calls on main thread */
404- if (_PyRuntime .ceval .pending .main_thread &&
405- PyThread_get_thread_ident () != _PyRuntime .ceval .pending .main_thread )
406- {
428+ if (PyThread_get_thread_ident () != _PyRuntime .main_thread ) {
407429 return 0 ;
408430 }
409431
@@ -428,24 +450,18 @@ make_pending_calls(void)
428450
429451 /* perform a bounded number of calls, in case of recursion */
430452 for (int i = 0 ; i < NPENDINGCALLS ; i ++ ) {
431- int j ;
432- int (* func )(void * );
453+ int (* func )(void * ) = NULL ;
433454 void * arg = NULL ;
434455
435456 /* pop one item off the queue while holding the lock */
436457 PyThread_acquire_lock (_PyRuntime .ceval .pending .lock , WAIT_LOCK );
437- j = _PyRuntime .ceval .pending .first ;
438- if (j == _PyRuntime .ceval .pending .last ) {
439- func = NULL ; /* Queue empty */
440- } else {
441- func = _PyRuntime .ceval .pending .calls [j ].func ;
442- arg = _PyRuntime .ceval .pending .calls [j ].arg ;
443- _PyRuntime .ceval .pending .first = (j + 1 ) % NPENDINGCALLS ;
444- }
458+ _pop_pending_call (& func , & arg );
445459 PyThread_release_lock (_PyRuntime .ceval .pending .lock );
460+
446461 /* having released the lock, perform the callback */
447- if (func == NULL )
462+ if (func == NULL ) {
448463 break ;
464+ }
449465 res = func (arg );
450466 if (res ) {
451467 goto error ;
0 commit comments