bpo-39877: 4th take_gil() fix for daemon threads (GH-19080) · python/cpython@a36adfa
@@ -196,8 +196,7 @@ tstate_must_exit(PyThreadState *tstate)
196196 tstate->interp->runtime to support calls from Python daemon threads.
197197 After Py_Finalize() has been called, tstate can be a dangling pointer:
198198 point to PyThreadState freed memory. */
199-_PyRuntimeState *runtime = &_PyRuntime;
200-PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime);
199+PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime);
201200return (finalizing != NULL && finalizing != tstate);
202201}
203202@@ -243,20 +242,23 @@ take_gil(PyThreadState *tstate)
243242 }
244243245244while (_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;
251246252247unsigned long interval = (gil->interval >= 1 ? gil->interval : 1);
248+int timed_out = 0;
253249COND_TIMED_WAIT(gil->cond, gil->mutex, interval, timed_out);
250+254251/* If we timed out and no switch occurred in the meantime, it is time
255252 to ask the GIL-holding thread to drop it. */
256253if (timed_out &&
257254_Py_atomic_load_relaxed(&gil->locked) &&
258255gil->switch_number == saved_switchnum)
259256 {
257+if (tstate_must_exit(tstate)) {
258+MUTEX_UNLOCK(gil->mutex);
259+PyThread_exit_thread();
260+ }
261+260262SET_GIL_DROP_REQUEST(ceval);
261263 }
262264 }
@@ -281,6 +283,19 @@ take_gil(PyThreadState *tstate)
281283MUTEX_UNLOCK(gil->switch_mutex);
282284#endif
283285286+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+284299if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) {
285300RESET_GIL_DROP_REQUEST(ceval, ceval2);
286301 }
@@ -293,27 +308,13 @@ take_gil(PyThreadState *tstate)
293308COMPUTE_EVAL_BREAKER(ceval, ceval2);
294309 }
295310296-int must_exit = tstate_must_exit(tstate);
297-298311/* Don't access tstate if the thread must exit */
299-if (!must_exit && tstate->async_exc != NULL) {
312+if (tstate->async_exc != NULL) {
300313_PyEval_SignalAsyncExc(tstate);
301314 }
302315303316MUTEX_UNLOCK(gil->mutex);
304317305-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-317318errno = err;
318319}
319320