@@ -196,8 +196,7 @@ tstate_must_exit(PyThreadState *tstate)
196
196
tstate->interp->runtime to support calls from Python daemon threads.
197
197
After Py_Finalize() has been called, tstate can be a dangling pointer:
198
198
point to PyThreadState freed memory. */
199
- _PyRuntimeState * runtime = & _PyRuntime ;
200
- PyThreadState * finalizing = _PyRuntimeState_GetFinalizing (runtime );
199
+ PyThreadState * finalizing = _PyRuntimeState_GetFinalizing (& _PyRuntime );
201
200
return (finalizing != NULL && finalizing != tstate );
202
201
}
203
202
@@ -243,20 +242,23 @@ take_gil(PyThreadState *tstate)
243
242
}
244
243
245
244
while (_Py_atomic_load_relaxed (& gil -> locked )) {
246
- int timed_out = 0 ;
247
- unsigned long saved_switchnum ;
248
-
249
- saved_switchnum = gil -> switch_number ;
250
-
245
+ unsigned long saved_switchnum = gil -> switch_number ;
251
246
252
247
unsigned long interval = (gil -> interval >= 1 ? gil -> interval : 1 );
248
+ int timed_out = 0 ;
253
249
COND_TIMED_WAIT (gil -> cond , gil -> mutex , interval , timed_out );
250
+
254
251
/* If we timed out and no switch occurred in the meantime, it is time
255
252
to ask the GIL-holding thread to drop it. */
256
253
if (timed_out &&
257
254
_Py_atomic_load_relaxed (& gil -> locked ) &&
258
255
gil -> switch_number == saved_switchnum )
259
256
{
257
+ if (tstate_must_exit (tstate )) {
258
+ MUTEX_UNLOCK (gil -> mutex );
259
+ PyThread_exit_thread ();
260
+ }
261
+
260
262
SET_GIL_DROP_REQUEST (ceval );
261
263
}
262
264
}
@@ -281,6 +283,19 @@ take_gil(PyThreadState *tstate)
281
283
MUTEX_UNLOCK (gil -> switch_mutex );
282
284
#endif
283
285
286
+ if (tstate_must_exit (tstate )) {
287
+ /* bpo-36475: If Py_Finalize() has been called and tstate is not
288
+ the thread which called Py_Finalize(), exit immediately the
289
+ thread.
290
+
291
+ This code path can be reached by a daemon thread which was waiting
292
+ in take_gil() while the main thread called
293
+ wait_for_thread_shutdown() from Py_Finalize(). */
294
+ MUTEX_UNLOCK (gil -> mutex );
295
+ drop_gil (ceval , ceval2 , tstate );
296
+ PyThread_exit_thread ();
297
+ }
298
+
284
299
if (_Py_atomic_load_relaxed (& ceval -> gil_drop_request )) {
285
300
RESET_GIL_DROP_REQUEST (ceval , ceval2 );
286
301
}
@@ -293,27 +308,13 @@ take_gil(PyThreadState *tstate)
293
308
COMPUTE_EVAL_BREAKER (ceval , ceval2 );
294
309
}
295
310
296
- int must_exit = tstate_must_exit (tstate );
297
-
298
311
/* Don't access tstate if the thread must exit */
299
- if (! must_exit && tstate -> async_exc != NULL ) {
312
+ if (tstate -> async_exc != NULL ) {
300
313
_PyEval_SignalAsyncExc (tstate );
301
314
}
302
315
303
316
MUTEX_UNLOCK (gil -> mutex );
304
317
305
- if (must_exit ) {
306
- /* bpo-36475: If Py_Finalize() has been called and tstate is not
307
- the thread which called Py_Finalize(), exit immediately the
308
- thread.
309
-
310
- This code path can be reached by a daemon thread which was waiting
311
- in take_gil() while the main thread called
312
- wait_for_thread_shutdown() from Py_Finalize(). */
313
- drop_gil (ceval , ceval2 , tstate );
314
- PyThread_exit_thread ();
315
- }
316
-
317
318
errno = err ;
318
319
}
319
320
0 commit comments