Skip to content

Commit

Permalink
bpo-40522: _PyThreadState_Swap() sets autoTSSkey (GH-19939)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
vstinner authored May 5, 2020
1 parent b4b5386 commit e838a93
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
20 changes: 18 additions & 2 deletions Include/internal/pycore_pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,18 @@ _Py_ThreadCanHandlePendingCalls(void)
/* Variable and macro for in-line access to current thread
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);
#endif
}

/* Get the current Python thread state.
Expand All @@ -62,8 +72,14 @@ static inline PyThreadState* _PyRuntimeState_GetThreadState(_PyRuntimeState *run
The caller must hold the GIL.
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);
#endif
}

/* Redefine PyThreadState_GET() as an alias to _PyThreadState_GET() */
Expand Down
13 changes: 13 additions & 0 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,9 +380,13 @@ PyEval_AcquireThread(PyThreadState *tstate)
take_gil(tstate);

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) {
Py_FatalError("non-NULL old thread state");
}
#endif
}

void
Expand Down Expand Up @@ -443,7 +447,12 @@ PyThreadState *
PyEval_SaveThread(void)
{
_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);
#endif
ensure_tstate_not_null(__func__, tstate);

struct _ceval_runtime_state *ceval = &runtime->ceval;
Expand Down Expand Up @@ -866,9 +875,13 @@ eval_frame_handle_pending(PyThreadState *tstate)

take_gil(tstate);

#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
(void)_PyThreadState_Swap(&runtime->gilstate, tstate);
#else
if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) {
Py_FatalError("orphan tstate");
}
#endif
}

/* Check for asynchronous exception. */
Expand Down
17 changes: 17 additions & 0 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_UncheckedGet(void)
{
Expand All @@ -975,7 +983,11 @@ PyThreadState_Get(void)
PyThreadState *
_PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *newts)
{
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
PyThreadState *oldts = _PyThreadState_GetTSS();
#else
PyThreadState *oldts = _PyRuntimeGILState_GetThreadState(gilstate);
#endif

_PyRuntimeGILState_SetThreadState(gilstate, newts);
/* It should not be possible for more than one thread state
Expand All @@ -993,6 +1005,9 @@ _PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *new
Py_FatalError("Invalid thread state for this thread");
errno = err;
}
#endif
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
PyThread_tss_set(&gilstate->autoTSSkey, newts);
#endif
return oldts;
}
Expand Down Expand Up @@ -1363,7 +1378,9 @@ PyGILState_Ensure(void)

/* Ensure that _PyEval_InitThreads() and _PyGILState_Init() have been
called by Py_Initialize() */
#ifndef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
assert(_PyEval_ThreadsInitialized(runtime));
#endif
assert(gilstate->autoInterpreterState);

PyThreadState *tcur = (PyThreadState *)PyThread_tss_get(&gilstate->autoTSSkey);
Expand Down

0 comments on commit e838a93

Please sign in to comment.