bpo-39877: Fix PyEval_RestoreThread() for daemon threads by vstinner · Pull Request #18808 · python/cpython
static inline void exit_thread_if_finalizing(PyThreadState *tstate) exit_thread_if_finalizing(_PyRuntimeState *runtime, PyThreadState *tstate) { _PyRuntimeState *runtime = tstate->interp->runtime; /* _Py_Finalizing is protected by the GIL */ if (runtime->finalizing != NULL && !_Py_CURRENTLY_FINALIZING(runtime, tstate)) { drop_gil(&runtime->ceval, tstate);
void
_PyRuntimeState *runtime = tstate->interp->runtime; /* bpo-39877: Access directly _PyRuntime rather than using tstate->interp->runtime: see PyEval_RestoreThread() for the rationale. */ _PyRuntimeState *runtime = &_PyRuntime; struct _ceval_runtime_state *ceval = &runtime->ceval;
/* Check someone has called PyEval_InitThreads() to create the lock */ assert(gil_created(&ceval->gil)); take_gil(ceval, tstate); exit_thread_if_finalizing(tstate); exit_thread_if_finalizing(runtime, tstate); if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) { Py_FatalError("PyEval_AcquireThread: non-NULL old thread state"); }
_PyRuntimeState *runtime = tstate->interp->runtime; /* bpo-39877: Access directly _PyRuntime rather than using tstate->interp->runtime to support calls from Python daemon threads after Py_Finalize() has been called. tstate can be a dangling pointer: point to freed memory (PyThreadState). */ _PyRuntimeState *runtime = &_PyRuntime; struct _ceval_runtime_state *ceval = &runtime->ceval; assert(gil_created(&ceval->gil));
int err = errno; take_gil(ceval, tstate); exit_thread_if_finalizing(tstate); exit_thread_if_finalizing(runtime, tstate); errno = err;
_PyThreadState_Swap(&runtime->gilstate, tstate);
/* Check if we should make a quick exit. */ exit_thread_if_finalizing(tstate); exit_thread_if_finalizing(runtime, tstate);
if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) { Py_FatalError("ceval: orphan tstate");