summaryrefslogtreecommitdiffstats
path: root/Python/ceval_gil.h
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-03-09 21:12:04 (GMT)
committerGitHub <noreply@github.com>2020-03-09 21:12:04 (GMT)
commit85f5a69ae1541271286bb0f0e0303aabf792dd5c (patch)
treea99a6bd9961520fd1db58646e0b56fc6c3cb7d87 /Python/ceval_gil.h
parent363fab83b8a0e6d924c7a7c577feec6a2812bb8c (diff)
downloadcpython-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.h41
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: