diff options
author | Victor Stinner <vstinner@python.org> | 2020-03-09 21:12:04 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-09 21:12:04 (GMT) |
commit | 85f5a69ae1541271286bb0f0e0303aabf792dd5c (patch) | |
tree | a99a6bd9961520fd1db58646e0b56fc6c3cb7d87 /Python/ceval_gil.h | |
parent | 363fab83b8a0e6d924c7a7c577feec6a2812bb8c (diff) | |
download | cpython-85f5a69ae1541271286bb0f0e0303aabf792dd5c.zip cpython-85f5a69ae1541271286bb0f0e0303aabf792dd5c.tar.gz cpython-85f5a69ae1541271286bb0f0e0303aabf792dd5c.tar.bz2 |
bpo-39877: Refactor take_gil() function (GH-18885)
* Remove ceval parameter of take_gil(): get it from tstate.
* Move exit_thread_if_finalizing() call inside take_gil(). Replace
exit_thread_if_finalizing() with tstate_must_exit(): the caller is
now responsible to call PyThread_exit_thread().
* Move is_tstate_valid() assertion inside take_gil(). Remove
is_tstate_valid(): inline code into take_gil().
* Move gil_created() assertion inside take_gil().
Diffstat (limited to 'Python/ceval_gil.h')
-rw-r--r-- | Python/ceval_gil.h | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/Python/ceval_gil.h b/Python/ceval_gil.h index 99d576d..03f04b9 100644 --- a/Python/ceval_gil.h +++ b/Python/ceval_gil.h @@ -180,17 +180,55 @@ drop_gil(struct _ceval_runtime_state *ceval, PyThreadState *tstate) #endif } + +/* Check if a Python thread must exit immediately, rather than taking the GIL + if Py_Finalize() has been called. + + When this function is called by a daemon thread after Py_Finalize() has been + called, the GIL does no longer exist. + + tstate must be non-NULL. */ +static inline int +tstate_must_exit(PyThreadState *tstate) +{ + /* bpo-39877: Access _PyRuntime directly 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 PyThreadState freed memory. */ + _PyRuntimeState *runtime = &_PyRuntime; + PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime); + return (finalizing != NULL && finalizing != tstate); +} + + /* Take the GIL. The function saves errno at entry and restores its value at exit. tstate must be non-NULL. */ static void -take_gil(struct _ceval_runtime_state *ceval, PyThreadState *tstate) +take_gil(PyThreadState *tstate) { int err = errno; + assert(tstate != NULL); + + /* Check if we should make a quick exit. */ + if (tstate_must_exit(tstate)) { + PyThread_exit_thread(); + } + + /* Ensure that tstate is valid: sanity check for PyEval_AcquireThread() and + PyEval_RestoreThread(). Detect if tstate memory was freed. */ + assert(!_PyMem_IsPtrFreed(tstate)); + assert(!_PyMem_IsPtrFreed(tstate->interp)); + + struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval; struct _gil_runtime_state *gil = &ceval->gil; + + /* Check that _PyEval_InitThreads() was called to create the lock */ + assert(gil_created(gil)); + MUTEX_LOCK(gil->mutex); if (!_Py_atomic_load_relaxed(&gil->locked)) { @@ -215,6 +253,7 @@ take_gil(struct _ceval_runtime_state *ceval, PyThreadState *tstate) SET_GIL_DROP_REQUEST(ceval); } } + _ready: #ifdef FORCE_SWITCHING /* This mutex must be taken before modifying gil->last_holder: |