mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
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().
This commit is contained in:
parent
363fab83b8
commit
85f5a69ae1
2 changed files with 53 additions and 66 deletions
|
@ -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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue