bpo-40522: _PyThreadState_Swap() sets autoTSSkey (GH-19939)

In the experimental isolated subinterpreters build mode,
_PyThreadState_GET() gets the autoTSSkey variable and
_PyThreadState_Swap() sets the autoTSSkey variable.

* Add _PyThreadState_GetTSS()
* _PyRuntimeState_GetThreadState() and _PyThreadState_GET()
  return _PyThreadState_GetTSS()
* PyEval_SaveThread() sets the autoTSSkey variable to current Python
  thread state rather than NULL.
* eval_frame_handle_pending() doesn't check that
  _PyThreadState_Swap() result is NULL.
* _PyThreadState_Swap() gets the current Python thread state with
  _PyThreadState_GetTSS() rather than
  _PyRuntimeGILState_GetThreadState().
* PyGILState_Ensure() no longer checks _PyEval_ThreadsInitialized()
  since it cannot access the current interpreter.
This commit is contained in:
Victor Stinner 2020-05-05 19:56:48 +02:00 committed by GitHub
parent b4b53868d7
commit e838a9324c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 2 deletions

View File

@ -49,8 +49,18 @@ _Py_ThreadCanHandlePendingCalls(void)
/* Variable and macro for in-line access to current thread /* Variable and macro for in-line access to current thread
and interpreter state */ and interpreter state */
static inline PyThreadState* _PyRuntimeState_GetThreadState(_PyRuntimeState *runtime) { #ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
PyAPI_FUNC(PyThreadState*) _PyThreadState_GetTSS(void);
#endif
static inline PyThreadState*
_PyRuntimeState_GetThreadState(_PyRuntimeState *runtime)
{
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
return _PyThreadState_GetTSS();
#else
return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->gilstate.tstate_current); return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->gilstate.tstate_current);
#endif
} }
/* Get the current Python thread state. /* Get the current Python thread state.
@ -62,8 +72,14 @@ static inline PyThreadState* _PyRuntimeState_GetThreadState(_PyRuntimeState *run
The caller must hold the GIL. The caller must hold the GIL.
See also PyThreadState_Get() and PyThreadState_GET(). */ See also PyThreadState_Get() and PyThreadState_GET(). */
static inline PyThreadState *_PyThreadState_GET(void) { static inline PyThreadState*
_PyThreadState_GET(void)
{
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
return _PyThreadState_GetTSS();
#else
return _PyRuntimeState_GetThreadState(&_PyRuntime); return _PyRuntimeState_GetThreadState(&_PyRuntime);
#endif
} }
/* Redefine PyThreadState_GET() as an alias to _PyThreadState_GET() */ /* Redefine PyThreadState_GET() as an alias to _PyThreadState_GET() */

View File

@ -380,9 +380,13 @@ PyEval_AcquireThread(PyThreadState *tstate)
take_gil(tstate); take_gil(tstate);
struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate; struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
(void)_PyThreadState_Swap(gilstate, tstate);
#else
if (_PyThreadState_Swap(gilstate, tstate) != NULL) { if (_PyThreadState_Swap(gilstate, tstate) != NULL) {
Py_FatalError("non-NULL old thread state"); Py_FatalError("non-NULL old thread state");
} }
#endif
} }
void void
@ -443,7 +447,12 @@ PyThreadState *
PyEval_SaveThread(void) PyEval_SaveThread(void)
{ {
_PyRuntimeState *runtime = &_PyRuntime; _PyRuntimeState *runtime = &_PyRuntime;
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
PyThreadState *old_tstate = _PyThreadState_GET();
PyThreadState *tstate = _PyThreadState_Swap(&runtime->gilstate, old_tstate);
#else
PyThreadState *tstate = _PyThreadState_Swap(&runtime->gilstate, NULL); PyThreadState *tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
#endif
ensure_tstate_not_null(__func__, tstate); ensure_tstate_not_null(__func__, tstate);
struct _ceval_runtime_state *ceval = &runtime->ceval; struct _ceval_runtime_state *ceval = &runtime->ceval;
@ -866,9 +875,13 @@ eval_frame_handle_pending(PyThreadState *tstate)
take_gil(tstate); take_gil(tstate);
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
(void)_PyThreadState_Swap(&runtime->gilstate, tstate);
#else
if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) { if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) {
Py_FatalError("orphan tstate"); Py_FatalError("orphan tstate");
} }
#endif
} }
/* Check for asynchronous exception. */ /* Check for asynchronous exception. */

View File

@ -956,6 +956,14 @@ _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate)
} }
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
PyThreadState*
_PyThreadState_GetTSS(void) {
return PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey);
}
#endif
PyThreadState * PyThreadState *
_PyThreadState_UncheckedGet(void) _PyThreadState_UncheckedGet(void)
{ {
@ -975,7 +983,11 @@ PyThreadState_Get(void)
PyThreadState * PyThreadState *
_PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *newts) _PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *newts)
{ {
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
PyThreadState *oldts = _PyThreadState_GetTSS();
#else
PyThreadState *oldts = _PyRuntimeGILState_GetThreadState(gilstate); PyThreadState *oldts = _PyRuntimeGILState_GetThreadState(gilstate);
#endif
_PyRuntimeGILState_SetThreadState(gilstate, newts); _PyRuntimeGILState_SetThreadState(gilstate, newts);
/* It should not be possible for more than one thread state /* It should not be possible for more than one thread state
@ -993,6 +1005,9 @@ _PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *new
Py_FatalError("Invalid thread state for this thread"); Py_FatalError("Invalid thread state for this thread");
errno = err; errno = err;
} }
#endif
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
PyThread_tss_set(&gilstate->autoTSSkey, newts);
#endif #endif
return oldts; return oldts;
} }
@ -1363,7 +1378,9 @@ PyGILState_Ensure(void)
/* Ensure that _PyEval_InitThreads() and _PyGILState_Init() have been /* Ensure that _PyEval_InitThreads() and _PyGILState_Init() have been
called by Py_Initialize() */ called by Py_Initialize() */
#ifndef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
assert(_PyEval_ThreadsInitialized(runtime)); assert(_PyEval_ThreadsInitialized(runtime));
#endif
assert(gilstate->autoInterpreterState); assert(gilstate->autoInterpreterState);
PyThreadState *tcur = (PyThreadState *)PyThread_tss_get(&gilstate->autoTSSkey); PyThreadState *tcur = (PyThreadState *)PyThread_tss_get(&gilstate->autoTSSkey);