Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-40522: Store tstate in a Thread Local Storage #23976

Open
wants to merge 1 commit into
base: master
from
Open
Changes from all commits
Commits
File filter
Filter file types
Jump to
Jump to file
Failed to load files.

Always

Just for now

@@ -53,6 +53,22 @@ _Py_ThreadCanHandlePendingCalls(void)
PyAPI_FUNC(PyThreadState*) _PyThreadState_GetTSS(void);
#endif


// Thread local storage for the current interpreter and the current Python
// thread state, if supported by the compiler.
#ifdef HAVE__THREAD_LOCAL_KEYWORD
// C11 _Thread_local keyword
# define _Py_HAVE_TSS_TSTATE
PyAPI_DATA(_Thread_local PyInterpreterState*) _Py_current_interp;
PyAPI_DATA(_Thread_local PyThreadState*) _Py_current_tstate;
#elif defined(__GNUC__) || defined(__clang__)
// GCC and clang __thread extension
# define _Py_HAVE_TSS_TSTATE
PyAPI_DATA(__thread PyInterpreterState*) _Py_current_interp;
PyAPI_DATA(__thread PyThreadState*) _Py_current_tstate;
#endif


static inline PyThreadState*
_PyRuntimeState_GetThreadState(_PyRuntimeState *runtime)
{
@@ -75,7 +91,9 @@ _PyRuntimeState_GetThreadState(_PyRuntimeState *runtime)
static inline PyThreadState*
_PyThreadState_GET(void)
{
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
#ifdef _Py_HAVE_TSS_TSTATE
return _Py_current_tstate;
#elif defined(EXPERIMENTAL_ISOLATED_SUBINTERPRETERS)
return _PyThreadState_GetTSS();
#else
return _PyRuntimeState_GetThreadState(&_PyRuntime);
@@ -110,11 +128,15 @@ _Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate)
See also _PyInterpreterState_Get()
and _PyGILState_GetInterpreterStateUnsafe(). */
static inline PyInterpreterState* _PyInterpreterState_GET(void) {
#ifdef _Py_HAVE_TSS_TSTATE
return _Py_current_interp;
#else
PyThreadState *tstate = _PyThreadState_GET();
#ifdef Py_DEBUG
_Py_EnsureTstateNotNULL(tstate);
#endif
return tstate->interp;
#endif
}


@@ -0,0 +1,2 @@
If Python is built with GCC or clang, the current interpreter and the current
Python thread state are now stored in a Thread Local Storage.
@@ -36,9 +36,16 @@ extern "C" {

#define _PyRuntimeGILState_GetThreadState(gilstate) \
((PyThreadState*)_Py_atomic_load_relaxed(&(gilstate)->tstate_current))
#define _PyRuntimeGILState_SetThreadState(gilstate, value) \
_Py_atomic_store_relaxed(&(gilstate)->tstate_current, \
(uintptr_t)(value))


#ifdef HAVE__THREAD_LOCAL_KEYWORD
_Thread_local PyInterpreterState *_Py_current_interp = NULL;
_Thread_local PyThreadState *_Py_current_tstate = NULL;
#elif defined(__GNUC__) || defined(__clang__)
# define _Py_HAVE_TSS_TSTATE
__thread PyInterpreterState *_Py_current_interp = NULL;
__thread PyThreadState *_Py_current_tstate = NULL;
#endif

/* Forward declarations */
static PyThreadState *_PyGILState_GetThisThreadState(struct _gilstate_runtime_state *gilstate);
@@ -603,6 +610,22 @@ PyInterpreterState_GetDict(PyInterpreterState *interp)
return interp->dict;
}


static void
set_current_tstate(struct _gilstate_runtime_state *gilstate,
PyThreadState *tstate)
{
#ifdef _Py_HAVE_TSS_TSTATE
_Py_current_tstate = tstate;
_Py_current_interp = tstate ? tstate->interp : NULL;
#endif
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
PyThread_tss_set(&gilstate->autoTSSkey, tstate);
#endif
_Py_atomic_store_relaxed(&gilstate->tstate_current, (uintptr_t)tstate);
}


static PyThreadState *
new_threadstate(PyInterpreterState *interp, int init)
{
@@ -929,7 +952,7 @@ _PyThreadState_DeleteCurrent(PyThreadState *tstate)
_Py_EnsureTstateNotNULL(tstate);
struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
tstate_delete_common(tstate, gilstate);
_PyRuntimeGILState_SetThreadState(gilstate, NULL);
set_current_tstate(gilstate, NULL);
_PyEval_ReleaseLock(tstate);
PyMem_RawFree(tstate);
}
@@ -1018,7 +1041,8 @@ _PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *new
PyThreadState *oldts = _PyRuntimeGILState_GetThreadState(gilstate);
#endif

_PyRuntimeGILState_SetThreadState(gilstate, newts);
set_current_tstate(gilstate, newts);

/* It should not be possible for more than one thread state
to be used for a thread. Check this the best we can in debug
builds.
@@ -1034,9 +1058,6 @@ _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;
}
@@ -17129,6 +17129,37 @@ $as_echo "#define HAVE_BUILTIN_ATOMIC 1" >>confdefs.h

fi

# Check for _Thread_local keyword
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _Thread_local keyword" >&5
$as_echo_n "checking for _Thread_local keyword... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
_Thread_local int val;
int main() {
val = 1;
return val;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
have__thread_local_keyword=yes
else
have__thread_local_keyword=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have__thread_local_keyword" >&5
$as_echo "$have__thread_local_keyword" >&6; }

if test "$have__thread_local_keyword" = yes; then

$as_echo "#define HAVE__THREAD_LOCAL_KEYWORD 1" >>confdefs.h

fi

# ensurepip option
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ensurepip" >&5
$as_echo_n "checking for ensurepip... " >&6; }
@@ -5606,6 +5606,24 @@ if test "$have_builtin_atomic" = yes; then
AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Has builtin __atomic_load_n() and __atomic_store_n() functions])
fi

# Check for _Thread_local keyword
AC_MSG_CHECKING(for _Thread_local keyword)
AC_LINK_IFELSE(
[
AC_LANG_SOURCE([[
_Thread_local int val;
int main() {
val = 1;
return val;
}
]])
],[have__thread_local_keyword=yes],[have__thread_local_keyword=no])
AC_MSG_RESULT($have__thread_local_keyword)

if test "$have__thread_local_keyword" = yes; then
AC_DEFINE(HAVE__THREAD_LOCAL_KEYWORD, 1, [Has C11 _Thread_local keyword])
fi

# ensurepip option
AC_MSG_CHECKING(for ensurepip)
AC_ARG_WITH(ensurepip,
@@ -1359,6 +1359,9 @@
/* Define to 1 if you have the `_getpty' function. */
#undef HAVE__GETPTY

/* Has C11 _Thread_local keyword */
#undef HAVE__THREAD_LOCAL_KEYWORD

/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
*/
#undef MAJOR_IN_MKDEV
ProTip! Use n and p to navigate between commits in a pull request.