gh-59956: Clarify GILState-related Code (gh-101161)

The objective of this change is to help make the GILState-related code easier to understand.  This mostly involves moving code around and some semantically equivalent refactors.  However, there are a also a small number of slight changes in structure and behavior:

* tstate_current is moved out of _PyRuntimeState.gilstate
* autoTSSkey is moved out of _PyRuntimeState.gilstate
* autoTSSkey is initialized earlier
* autoTSSkey is re-initialized (after fork) earlier

https://github.com/python/cpython/issues/59956
This commit is contained in:
Eric Snow 2023-01-19 16:04:14 -07:00 committed by GitHub
parent 8a2d4f4e8e
commit 6036c3e856
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 373 additions and 250 deletions

View File

@ -114,11 +114,7 @@ struct _ts {
PyThreadState *next;
PyInterpreterState *interp;
/* Has been initialized to a safe state.
In order to be effective, this must be set to 0 during or right
after allocation. */
int _initialized;
int _status;
int py_recursion_remaining;
int py_recursion_limit;

View File

@ -69,7 +69,7 @@ extern void _PyThread_FiniType(PyInterpreterState *interp);
extern void _Py_Deepfreeze_Fini(void);
extern void _PyArg_Fini(void);
extern PyStatus _PyGILState_Init(_PyRuntimeState *runtime);
extern PyStatus _PyGILState_Init(PyInterpreterState *interp);
extern PyStatus _PyGILState_SetTstate(PyThreadState *tstate);
extern void _PyGILState_Fini(PyInterpreterState *interp);

View File

@ -67,12 +67,12 @@ _Py_ThreadCanHandlePendingCalls(void)
static inline PyThreadState*
_PyRuntimeState_GetThreadState(_PyRuntimeState *runtime)
{
return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->gilstate.tstate_current);
return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->tstate_current);
}
/* Get the current Python thread state.
Efficient macro reading directly the 'gilstate.tstate_current' atomic
Efficient macro reading directly the 'tstate_current' atomic
variable. The macro is unsafe: it does not check for error and it can
return NULL.
@ -120,7 +120,7 @@ static inline PyInterpreterState* _PyInterpreterState_GET(void) {
// PyThreadState functions
PyAPI_FUNC(void) _PyThreadState_SetCurrent(PyThreadState *tstate);
PyAPI_FUNC(void) _PyThreadState_Bind(PyThreadState *tstate);
// We keep this around exclusively for stable ABI compatibility.
PyAPI_FUNC(void) _PyThreadState_Init(
PyThreadState *tstate);
@ -139,17 +139,28 @@ _PyThreadState_UpdateTracingState(PyThreadState *tstate)
}
/* PyThreadState status */
#define PyThreadState_UNINITIALIZED 0
/* Has been initialized to a safe state.
In order to be effective, this must be set to 0 during or right
after allocation. */
#define PyThreadState_INITIALIZED 1
#define PyThreadState_BOUND 2
#define PyThreadState_UNBOUND 3
/* Other */
PyAPI_FUNC(PyThreadState *) _PyThreadState_Swap(
struct _gilstate_runtime_state *gilstate,
_PyRuntimeState *runtime,
PyThreadState *newts);
PyAPI_FUNC(PyStatus) _PyInterpreterState_Enable(_PyRuntimeState *runtime);
#ifdef HAVE_FORK
extern PyStatus _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime);
extern PyStatus _PyGILState_Reinit(_PyRuntimeState *runtime);
extern void _PySignal_AfterFork(void);
#endif

View File

@ -41,15 +41,11 @@ struct _gilstate_runtime_state {
/* bpo-26558: Flag to disable PyGILState_Check().
If set to non-zero, PyGILState_Check() always return 1. */
int check_enabled;
/* Assuming the current thread holds the GIL, this is the
PyThreadState for the current thread. */
_Py_atomic_address tstate_current;
/* The single PyInterpreterState used by this process'
GILState implementation
*/
/* TODO: Given interp_main, it may be possible to kill this ref */
PyInterpreterState *autoInterpreterState;
Py_tss_t autoTSSkey;
};
/* Runtime audit hook state */
@ -124,6 +120,12 @@ typedef struct pyruntimestate {
unsigned long main_thread;
/* Assuming the current thread holds the GIL, this is the
PyThreadState for the current thread. */
_Py_atomic_address tstate_current;
/* Used for the thread state bound to the current thread. */
Py_tss_t autoTSSkey;
PyWideStringList orig_argv;
struct _parser_runtime_state parser;

View File

@ -33,6 +33,9 @@ extern "C" {
until _PyInterpreterState_Enable() is called. */ \
.next_id = -1, \
}, \
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \
in accordance with the specification. */ \
.autoTSSkey = Py_tss_NEEDS_INIT, \
.parser = _parser_runtime_state_INIT, \
.imports = { \
.lock = { \
@ -49,9 +52,6 @@ extern "C" {
}, \
.gilstate = { \
.check_enabled = 1, \
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \
in accordance with the specification. */ \
.autoTSSkey = Py_tss_NEEDS_INIT, \
}, \
.dtoa = _dtoa_runtime_state_INIT(runtime), \
.fileutils = { \

View File

@ -1074,13 +1074,7 @@ thread_run(void *boot_raw)
PyThreadState *tstate;
tstate = boot->tstate;
tstate->thread_id = PyThread_get_thread_ident();
#ifdef PY_HAVE_THREAD_NATIVE_ID
tstate->native_thread_id = PyThread_get_thread_native_id();
#else
tstate->native_thread_id = 0;
#endif
_PyThreadState_SetCurrent(tstate);
_PyThreadState_Bind(tstate);
PyEval_AcquireThread(tstate);
tstate->interp->threads.count++;

View File

@ -587,7 +587,7 @@ PyOS_AfterFork_Child(void)
PyStatus status;
_PyRuntimeState *runtime = &_PyRuntime;
status = _PyGILState_Reinit(runtime);
status = _PyRuntimeState_ReInitThreads(runtime);
if (_PyStatus_EXCEPTION(status)) {
goto fatal_error;
}
@ -611,11 +611,6 @@ PyOS_AfterFork_Child(void)
_PySignal_AfterFork();
status = _PyRuntimeState_ReInitThreads(runtime);
if (_PyStatus_EXCEPTION(status)) {
goto fatal_error;
}
status = _PyInterpreterState_DeleteExceptMain(runtime);
if (_PyStatus_EXCEPTION(status)) {
goto fatal_error;

View File

@ -581,8 +581,7 @@ PyEval_AcquireThread(PyThreadState *tstate)
take_gil(tstate);
struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
if (_PyThreadState_Swap(gilstate, tstate) != NULL) {
if (_PyThreadState_Swap(tstate->interp->runtime, tstate) != NULL) {
Py_FatalError("non-NULL old thread state");
}
}
@ -593,7 +592,7 @@ PyEval_ReleaseThread(PyThreadState *tstate)
assert(is_tstate_valid(tstate));
_PyRuntimeState *runtime = tstate->interp->runtime;
PyThreadState *new_tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
PyThreadState *new_tstate = _PyThreadState_Swap(runtime, NULL);
if (new_tstate != tstate) {
Py_FatalError("wrong thread state");
}
@ -643,7 +642,7 @@ PyThreadState *
PyEval_SaveThread(void)
{
_PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
PyThreadState *tstate = _PyThreadState_Swap(runtime, NULL);
_Py_EnsureTstateNotNULL(tstate);
struct _ceval_runtime_state *ceval = &runtime->ceval;
@ -660,8 +659,7 @@ PyEval_RestoreThread(PyThreadState *tstate)
take_gil(tstate);
struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
_PyThreadState_Swap(gilstate, tstate);
_PyThreadState_Swap(tstate->interp->runtime, tstate);
}
@ -965,7 +963,7 @@ _Py_HandlePending(PyThreadState *tstate)
/* GIL drop request */
if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->gil_drop_request)) {
/* Give another thread a chance */
if (_PyThreadState_Swap(&runtime->gilstate, NULL) != tstate) {
if (_PyThreadState_Swap(runtime, NULL) != tstate) {
Py_FatalError("tstate mix-up");
}
drop_gil(ceval, interp_ceval_state, tstate);
@ -974,7 +972,7 @@ _Py_HandlePending(PyThreadState *tstate)
take_gil(tstate);
if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) {
if (_PyThreadState_Swap(runtime, tstate) != NULL) {
Py_FatalError("orphan tstate");
}
}

View File

@ -675,12 +675,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
const PyConfig *src_config,
PyThreadState **tstate_p)
{
/* Auto-thread-state API */
PyStatus status = _PyGILState_Init(runtime);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
PyStatus status;
PyInterpreterState *interp = PyInterpreterState_New();
if (interp == NULL) {
return _PyStatus_ERR("can't make main interpreter");
@ -692,6 +687,12 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
return status;
}
/* Auto-thread-state API */
status = _PyGILState_Init(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
init_interp_settings(interp, &config);
@ -1795,10 +1796,8 @@ finalize_interp_clear(PyThreadState *tstate)
static void
finalize_interp_delete(PyInterpreterState *interp)
{
if (_Py_IsMainInterpreter(interp)) {
/* Cleanup auto-thread-state */
_PyGILState_Fini(interp);
}
/* We can't call _PyEval_FiniGIL() here because destroying the GIL lock can
fail when it is being awaited by another running daemon thread (see

View File

@ -10,7 +10,7 @@
#include "pycore_pyerrors.h"
#include "pycore_pylifecycle.h"
#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_pystate.h"
#include "pycore_runtime_init.h" // _PyRuntimeState_INIT
#include "pycore_sysmodule.h"
@ -37,16 +37,205 @@ to avoid the expense of doing their own locking).
extern "C" {
#endif
#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))
/* Forward declarations */
static PyThreadState *_PyGILState_GetThisThreadState(struct _gilstate_runtime_state *gilstate);
static void _PyThreadState_Delete(PyThreadState *tstate, int check_current);
/* the current thread state */
static inline PyThreadState *
current_fast_get(_PyRuntimeState *runtime)
{
// The GIL must be held by the current thread.
return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->tstate_current);
}
static inline void
current_fast_set(_PyRuntimeState *runtime, PyThreadState *tstate)
{
// The GIL must be held by the current thread.
assert(tstate != NULL);
_Py_atomic_store_relaxed(&runtime->tstate_current, (uintptr_t)tstate);
}
static inline void
current_fast_clear(_PyRuntimeState *runtime)
{
// The GIL must be held by the current thread.
_Py_atomic_store_relaxed(&runtime->tstate_current, (uintptr_t)NULL);
}
static int
current_tss_initialized(_PyRuntimeState *runtime)
{
return PyThread_tss_is_created(&runtime->autoTSSkey);
}
static PyStatus
current_tss_init(_PyRuntimeState *runtime)
{
assert(!current_tss_initialized(runtime));
if (PyThread_tss_create(&runtime->autoTSSkey) != 0) {
return _PyStatus_NO_MEMORY();
}
return _PyStatus_OK();
}
static void
current_tss_fini(_PyRuntimeState *runtime)
{
assert(current_tss_initialized(runtime));
PyThread_tss_delete(&runtime->autoTSSkey);
}
static inline PyThreadState *
current_tss_get(_PyRuntimeState *runtime)
{
assert(current_tss_initialized(runtime));
return (PyThreadState *)PyThread_tss_get(&runtime->autoTSSkey);
}
static inline int
_current_tss_set(_PyRuntimeState *runtime, PyThreadState *tstate)
{
assert(tstate != NULL);
assert(current_tss_initialized(runtime));
return PyThread_tss_set(&runtime->autoTSSkey, (void *)tstate);
}
static inline void
current_tss_set(_PyRuntimeState *runtime, PyThreadState *tstate)
{
if (_current_tss_set(runtime, tstate) != 0) {
Py_FatalError("failed to set current tstate (TSS)");
}
}
static inline void
current_tss_clear(_PyRuntimeState *runtime)
{
assert(current_tss_initialized(runtime));
if (PyThread_tss_set(&runtime->autoTSSkey, NULL) != 0) {
Py_FatalError("failed to clear current tstate (TSS)");
}
}
#ifdef HAVE_FORK
/* Reset the TSS key - called by PyOS_AfterFork_Child().
* This should not be necessary, but some - buggy - pthread implementations
* don't reset TSS upon fork(), see issue #10517.
*/
static PyStatus
current_tss_reinit(_PyRuntimeState *runtime)
{
if (!current_tss_initialized(runtime)) {
return _PyStatus_OK();
}
PyThreadState *tstate = current_tss_get(runtime);
current_tss_fini(runtime);
PyStatus status = current_tss_init(runtime);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
/* If the thread had an associated auto thread state, reassociate it with
* the new key. */
if (tstate && _current_tss_set(runtime, tstate) != 0) {
return _PyStatus_ERR("failed to set autoTSSkey");
}
return _PyStatus_OK();
}
#endif
static void
bind_tstate(PyThreadState *tstate)
{
assert(tstate != NULL);
assert(tstate->_status == PyThreadState_INITIALIZED);
assert(tstate->thread_id == 0);
assert(tstate->native_thread_id == 0);
_PyRuntimeState *runtime = tstate->interp->runtime;
/* Stick the thread state for this thread in thread specific storage.
The only situation where you can legitimately have more than one
thread state for an OS level thread is when there are multiple
interpreters.
You shouldn't really be using the PyGILState_ APIs anyway (see issues
#10915 and #15751).
The first thread state created for that given OS level thread will
"win", which seems reasonable behaviour.
*/
/* When a thread state is created for a thread by some mechanism
other than PyGILState_Ensure(), it's important that the GILState
machinery knows about it so it doesn't try to create another
thread state for the thread.
(This is a better fix for SF bug #1010677 than the first one attempted.)
*/
// XXX Skipping like this does not play nice with multiple interpreters.
if (current_tss_get(runtime) == NULL) {
current_tss_set(runtime, tstate);
}
tstate->thread_id = PyThread_get_thread_ident();
#ifdef PY_HAVE_THREAD_NATIVE_ID
tstate->native_thread_id = PyThread_get_thread_native_id();
#endif
tstate->_status = PyThreadState_BOUND;
}
static void
unbind_tstate(PyThreadState *tstate)
{
assert(tstate != NULL);
assert(tstate->_status == PyThreadState_BOUND);
assert(tstate->thread_id > 0);
#ifdef PY_HAVE_THREAD_NATIVE_ID
assert(tstate->native_thread_id > 0);
#endif
_PyRuntimeState *runtime = tstate->interp->runtime;
if (current_tss_initialized(runtime) &&
tstate == current_tss_get(runtime))
{
current_tss_clear(runtime);
}
// We leave thread_id and native_thraed_id alone
// since they can be useful for debugging.
// Check the `_status` field to know if these values
// are still valid.
tstate->_status = PyThreadState_UNBOUND;
}
/* This is not exported, as it is not reliable! It can only
ever be compared to the state for the *current* thread.
* If not equal, then it doesn't matter that the actual
value may change immediately after comparison, as it can't
possibly change to the current thread's state.
* If equal, then the current thread holds the lock, so the value can't
change until we yield the lock.
*/
static int
holds_gil(PyThreadState *tstate)
{
// XXX Fall back to tstate->interp->runtime->ceval.gil.last_holder
// (and tstate->interp->runtime->ceval.gil.locked).
assert(tstate != NULL);
_PyRuntimeState *runtime = tstate->interp->runtime;
/* Must be the tstate for this thread */
assert(tstate == current_tss_get(runtime));
return tstate == current_fast_get(runtime);
}
/* the global runtime */
/* Suppress deprecation warning for PyBytesObject.ob_shash */
_Py_COMP_DIAG_PUSH
_Py_COMP_DIAG_IGNORE_DEPR_DECLS
@ -166,6 +355,13 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
// Reset to _PyRuntimeState_INIT.
memcpy(runtime, &initial, sizeof(*runtime));
}
PyStatus status = current_tss_init(runtime);
if (_PyStatus_EXCEPTION(status)) {
_PyRuntimeState_Fini(runtime);
return status;
}
init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head,
unicode_next_index, lock1, lock2, lock3, lock4);
@ -175,6 +371,10 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
void
_PyRuntimeState_Fini(_PyRuntimeState *runtime)
{
if (current_tss_initialized(runtime)) {
current_tss_fini(runtime);
}
/* Force the allocator used by _PyRuntimeState_Init(). */
PyMemAllocatorEx old_alloc;
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
@ -227,15 +427,17 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
return _PyStatus_ERR("Failed to reinitialize runtime locks");
}
PyStatus status = current_tss_reinit(runtime);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
return _PyStatus_OK();
}
#endif
/* Forward declaration */
static void _PyGILState_NoteThreadState(
struct _gilstate_runtime_state *gilstate, PyThreadState* tstate);
PyStatus
_PyInterpreterState_Enable(_PyRuntimeState *runtime)
{
@ -318,7 +520,8 @@ PyInterpreterState *
PyInterpreterState_New(void)
{
PyInterpreterState *interp;
PyThreadState *tstate = _PyThreadState_GET();
_PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *tstate = current_fast_get(runtime);
/* tstate is NULL when Py_InitializeFromConfig() calls
PyInterpreterState_New() to create the main interpreter. */
@ -335,7 +538,6 @@ PyInterpreterState_New(void)
}
/* Don't get runtime from tstate since tstate can be NULL. */
_PyRuntimeState *runtime = &_PyRuntime;
struct pyinterpreters *interpreters = &runtime->interpreters;
/* We completely serialize creation of multiple interpreters, since
@ -483,7 +685,7 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
// Use the current Python thread state to call audit hooks and to collect
// garbage. It can be different than the current Python thread state
// of 'interp'.
PyThreadState *current_tstate = _PyThreadState_GET();
PyThreadState *current_tstate = current_fast_get(interp->runtime);
interpreter_clear(interp, current_tstate);
}
@ -518,7 +720,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
_PyEval_FiniState(&interp->ceval);
/* Delete current thread. After this, many C API calls become crashy. */
_PyThreadState_Swap(&runtime->gilstate, NULL);
_PyThreadState_Swap(runtime, NULL);
HEAD_LOCK(runtime);
PyInterpreterState **p;
@ -558,10 +760,9 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
PyStatus
_PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
{
struct _gilstate_runtime_state *gilstate = &runtime->gilstate;
struct pyinterpreters *interpreters = &runtime->interpreters;
PyThreadState *tstate = _PyThreadState_Swap(gilstate, NULL);
PyThreadState *tstate = _PyThreadState_Swap(runtime, NULL);
if (tstate != NULL && tstate->interp != interpreters->main) {
return _PyStatus_ERR("not main interpreter");
}
@ -591,7 +792,7 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
if (interpreters->head == NULL) {
return _PyStatus_ERR("missing main interpreter");
}
_PyThreadState_Swap(gilstate, tstate);
_PyThreadState_Swap(runtime, tstate);
return _PyStatus_OK();
}
#endif
@ -600,7 +801,7 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
PyInterpreterState *
PyInterpreterState_Get(void)
{
PyThreadState *tstate = _PyThreadState_GET();
PyThreadState *tstate = current_fast_get(&_PyRuntime);
_Py_EnsureTstateNotNULL(tstate);
PyInterpreterState *interp = tstate->interp;
if (interp == NULL) {
@ -691,8 +892,8 @@ void
_PyInterpreterState_IDDecref(PyInterpreterState *interp)
{
assert(interp->id_mutex != NULL);
_PyRuntimeState *runtime = interp->runtime;
struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate;
PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK);
assert(interp->id_refcount != 0);
interp->id_refcount -= 1;
@ -703,9 +904,9 @@ _PyInterpreterState_IDDecref(PyInterpreterState *interp)
// XXX Using the "head" thread isn't strictly correct.
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
// XXX Possible GILState issues?
PyThreadState *save_tstate = _PyThreadState_Swap(gilstate, tstate);
PyThreadState *save_tstate = _PyThreadState_Swap(runtime, tstate);
Py_EndInterpreter(tstate);
_PyThreadState_Swap(gilstate, save_tstate);
_PyThreadState_Swap(runtime, save_tstate);
}
}
@ -790,7 +991,7 @@ init_threadstate(PyThreadState *tstate,
PyInterpreterState *interp, uint64_t id,
PyThreadState *next)
{
if (tstate->_initialized) {
if (tstate->_status != PyThreadState_UNINITIALIZED) {
Py_FatalError("thread state already initialized");
}
@ -809,10 +1010,7 @@ init_threadstate(PyThreadState *tstate,
tstate->next = next;
assert(tstate->prev == NULL);
tstate->thread_id = PyThread_get_thread_ident();
#ifdef PY_HAVE_THREAD_NATIVE_ID
tstate->native_thread_id = PyThread_get_thread_native_id();
#endif
// thread_id and native_thread_id are set in bind_tstate().
tstate->py_recursion_limit = interp->ceval.recursion_limit,
tstate->py_recursion_remaining = interp->ceval.recursion_limit,
@ -820,12 +1018,16 @@ init_threadstate(PyThreadState *tstate,
tstate->exc_info = &tstate->exc_state;
// PyGILState_Release must not try to delete this thread state.
// This is cleared when PyGILState_Ensure() creates the thread sate.
tstate->gilstate_counter = 1;
tstate->cframe = &tstate->root_cframe;
tstate->datastack_chunk = NULL;
tstate->datastack_top = NULL;
tstate->datastack_limit = NULL;
tstate->_initialized = 1;
tstate->_status = PyThreadState_INITIALIZED;
}
static PyThreadState *
@ -884,11 +1086,12 @@ PyThreadState_New(PyInterpreterState *interp)
{
PyThreadState *tstate = new_threadstate(interp);
if (tstate) {
_PyThreadState_SetCurrent(tstate);
bind_tstate(tstate);
}
return tstate;
}
// This must be followed by a call to _PyThreadState_Bind();
PyThreadState *
_PyThreadState_Prealloc(PyInterpreterState *interp)
{
@ -904,9 +1107,9 @@ _PyThreadState_Init(PyThreadState *tstate)
}
void
_PyThreadState_SetCurrent(PyThreadState *tstate)
_PyThreadState_Bind(PyThreadState *tstate)
{
_PyGILState_NoteThreadState(&tstate->interp->runtime->gilstate, tstate);
bind_tstate(tstate);
}
PyObject*
@ -968,7 +1171,7 @@ PyState_AddModule(PyObject* module, PyModuleDef* def)
return -1;
}
PyThreadState *tstate = _PyThreadState_GET();
PyThreadState *tstate = current_fast_get(&_PyRuntime);
PyInterpreterState *interp = tstate->interp;
Py_ssize_t index = def->m_base.m_index;
if (interp->modules_by_index &&
@ -984,7 +1187,7 @@ PyState_AddModule(PyObject* module, PyModuleDef* def)
int
PyState_RemoveModule(PyModuleDef* def)
{
PyThreadState *tstate = _PyThreadState_GET();
PyThreadState *tstate = current_fast_get(&_PyRuntime);
PyInterpreterState *interp = tstate->interp;
if (def->m_slots) {
@ -1089,8 +1292,7 @@ PyThreadState_Clear(PyThreadState *tstate)
/* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */
static void
tstate_delete_common(PyThreadState *tstate,
struct _gilstate_runtime_state *gilstate)
tstate_delete_common(PyThreadState *tstate)
{
_Py_EnsureTstateNotNULL(tstate);
PyInterpreterState *interp = tstate->interp;
@ -1111,11 +1313,10 @@ tstate_delete_common(PyThreadState *tstate,
}
HEAD_UNLOCK(runtime);
if (gilstate->autoInterpreterState &&
PyThread_tss_get(&gilstate->autoTSSkey) == tstate)
{
PyThread_tss_set(&gilstate->autoTSSkey, NULL);
}
// XXX Do this in PyThreadState_Swap() (and assert not-equal here)?
unbind_tstate(tstate);
// XXX Move to PyThreadState_Clear()?
_PyStackChunk *chunk = tstate->datastack_chunk;
tstate->datastack_chunk = NULL;
while (chunk != NULL) {
@ -1128,13 +1329,12 @@ tstate_delete_common(PyThreadState *tstate,
static void
_PyThreadState_Delete(PyThreadState *tstate, int check_current)
{
struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
if (check_current) {
if (tstate == _PyRuntimeGILState_GetThreadState(gilstate)) {
if (tstate == current_fast_get(tstate->interp->runtime)) {
_Py_FatalErrorFormat(__func__, "tstate %p is still current", tstate);
}
}
tstate_delete_common(tstate, gilstate);
tstate_delete_common(tstate);
free_threadstate(tstate);
}
@ -1150,9 +1350,8 @@ void
_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);
tstate_delete_common(tstate);
current_fast_clear(tstate->interp->runtime);
_PyEval_ReleaseLock(tstate);
free_threadstate(tstate);
}
@ -1160,8 +1359,7 @@ _PyThreadState_DeleteCurrent(PyThreadState *tstate)
void
PyThreadState_DeleteCurrent(void)
{
struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate;
PyThreadState *tstate = _PyRuntimeGILState_GetThreadState(gilstate);
PyThreadState *tstate = current_fast_get(&_PyRuntime);
_PyThreadState_DeleteCurrent(tstate);
}
@ -1211,38 +1409,45 @@ _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate)
PyThreadState *
_PyThreadState_UncheckedGet(void)
{
return _PyThreadState_GET();
return current_fast_get(&_PyRuntime);
}
PyThreadState *
PyThreadState_Get(void)
{
PyThreadState *tstate = _PyThreadState_GET();
PyThreadState *tstate = current_fast_get(&_PyRuntime);
_Py_EnsureTstateNotNULL(tstate);
return tstate;
}
PyThreadState *
_PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *newts)
_PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts)
{
PyThreadState *oldts = _PyRuntimeGILState_GetThreadState(gilstate);
PyThreadState *oldts = current_fast_get(runtime);
_PyRuntimeGILState_SetThreadState(gilstate, newts);
if (newts == NULL) {
current_fast_clear(runtime);
}
else {
current_fast_set(runtime, 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.
*/
// XXX The above isn't true when multiple interpreters are involved.
#if defined(Py_DEBUG)
if (newts) {
if (newts && current_tss_initialized(runtime)) {
/* This can be called from PyEval_RestoreThread(). Similar
to it, we need to ensure errno doesn't change.
*/
int err = errno;
PyThreadState *check = _PyGILState_GetThisThreadState(gilstate);
if (check && check->interp == newts->interp && check != newts)
PyThreadState *check = current_tss_get(runtime);
if (check && check->interp == newts->interp && check != newts) {
Py_FatalError("Invalid thread state for this thread");
}
errno = err;
}
#endif
@ -1252,7 +1457,7 @@ _PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *new
PyThreadState *
PyThreadState_Swap(PyThreadState *newts)
{
return _PyThreadState_Swap(&_PyRuntime.gilstate, newts);
return _PyThreadState_Swap(&_PyRuntime, newts);
}
/* An extension mechanism to store arbitrary additional per-thread state.
@ -1278,7 +1483,7 @@ _PyThreadState_GetDict(PyThreadState *tstate)
PyObject *
PyThreadState_GetDict(void)
{
PyThreadState *tstate = _PyThreadState_GET();
PyThreadState *tstate = current_fast_get(&_PyRuntime);
if (tstate == NULL) {
return NULL;
}
@ -1401,7 +1606,8 @@ PyThreadState_Next(PyThreadState *tstate) {
PyObject *
_PyThread_CurrentFrames(void)
{
PyThreadState *tstate = _PyThreadState_GET();
_PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *tstate = current_fast_get(runtime);
if (_PySys_Audit(tstate, "sys._current_frames", NULL) < 0) {
return NULL;
}
@ -1417,7 +1623,6 @@ _PyThread_CurrentFrames(void)
* Because these lists can mutate even when the GIL is held, we
* need to grab head_mutex for the duration.
*/
_PyRuntimeState *runtime = tstate->interp->runtime;
HEAD_LOCK(runtime);
PyInterpreterState *i;
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
@ -1457,7 +1662,8 @@ done:
PyObject *
_PyThread_CurrentExceptions(void)
{
PyThreadState *tstate = _PyThreadState_GET();
_PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *tstate = current_fast_get(runtime);
_Py_EnsureTstateNotNULL(tstate);
@ -1476,7 +1682,6 @@ _PyThread_CurrentExceptions(void)
* Because these lists can mutate even when the GIL is held, we
* need to grab head_mutex for the duration.
*/
_PyRuntimeState *runtime = tstate->interp->runtime;
HEAD_LOCK(runtime);
PyInterpreterState *i;
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
@ -1515,40 +1720,37 @@ done:
/* Python "auto thread state" API. */
/* Keep this as a static, as it is not reliable! It can only
ever be compared to the state for the *current* thread.
* If not equal, then it doesn't matter that the actual
value may change immediately after comparison, as it can't
possibly change to the current thread's state.
* If equal, then the current thread holds the lock, so the value can't
change until we yield the lock.
*/
static int
PyThreadState_IsCurrent(PyThreadState *tstate)
{
/* Must be the tstate for this thread */
struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate;
assert(_PyGILState_GetThisThreadState(gilstate) == tstate);
return tstate == _PyRuntimeGILState_GetThreadState(gilstate);
}
/* Internal initialization/finalization functions called by
Py_Initialize/Py_FinalizeEx
*/
PyStatus
_PyGILState_Init(_PyRuntimeState *runtime)
_PyGILState_Init(PyInterpreterState *interp)
{
struct _gilstate_runtime_state *gilstate = &runtime->gilstate;
if (PyThread_tss_create(&gilstate->autoTSSkey) != 0) {
return _PyStatus_NO_MEMORY();
if (!_Py_IsMainInterpreter(interp)) {
/* Currently, PyGILState is shared by all interpreters. The main
* interpreter is responsible to initialize it. */
return _PyStatus_OK();
}
// PyThreadState_New() calls _PyGILState_NoteThreadState() which does
// nothing before autoInterpreterState is set.
assert(gilstate->autoInterpreterState == NULL);
_PyRuntimeState *runtime = interp->runtime;
assert(current_tss_get(runtime) == NULL);
assert(runtime->gilstate.autoInterpreterState == NULL);
runtime->gilstate.autoInterpreterState = interp;
return _PyStatus_OK();
}
void
_PyGILState_Fini(PyInterpreterState *interp)
{
if (!_Py_IsMainInterpreter(interp)) {
/* Currently, PyGILState is shared by all interpreters. The main
* interpreter is responsible to initialize it. */
return;
}
interp->runtime->gilstate.autoInterpreterState = NULL;
}
// XXX Drop this.
PyStatus
_PyGILState_SetTstate(PyThreadState *tstate)
{
@ -1561,14 +1763,12 @@ _PyGILState_SetTstate(PyThreadState *tstate)
* interpreter is responsible to initialize it. */
return _PyStatus_OK();
}
_PyRuntimeState *runtime = tstate->interp->runtime;
struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
assert(runtime->gilstate.autoInterpreterState == tstate->interp);
assert(current_tss_get(runtime) == tstate);
assert(tstate->gilstate_counter == 1);
gilstate->autoInterpreterState = tstate->interp;
assert(PyThread_tss_get(&gilstate->autoTSSkey) == NULL);
assert(tstate->gilstate_counter == 0);
_PyGILState_NoteThreadState(gilstate, tstate);
return _PyStatus_OK();
}
@ -1578,118 +1778,42 @@ _PyGILState_GetInterpreterStateUnsafe(void)
return _PyRuntime.gilstate.autoInterpreterState;
}
void
_PyGILState_Fini(PyInterpreterState *interp)
{
struct _gilstate_runtime_state *gilstate = &interp->runtime->gilstate;
PyThread_tss_delete(&gilstate->autoTSSkey);
gilstate->autoInterpreterState = NULL;
}
#ifdef HAVE_FORK
/* Reset the TSS key - called by PyOS_AfterFork_Child().
* This should not be necessary, but some - buggy - pthread implementations
* don't reset TSS upon fork(), see issue #10517.
*/
PyStatus
_PyGILState_Reinit(_PyRuntimeState *runtime)
{
struct _gilstate_runtime_state *gilstate = &runtime->gilstate;
PyThreadState *tstate = _PyGILState_GetThisThreadState(gilstate);
PyThread_tss_delete(&gilstate->autoTSSkey);
if (PyThread_tss_create(&gilstate->autoTSSkey) != 0) {
return _PyStatus_NO_MEMORY();
}
/* If the thread had an associated auto thread state, reassociate it with
* the new key. */
if (tstate &&
PyThread_tss_set(&gilstate->autoTSSkey, (void *)tstate) != 0)
{
return _PyStatus_ERR("failed to set autoTSSkey");
}
return _PyStatus_OK();
}
#endif
/* When a thread state is created for a thread by some mechanism other than
PyGILState_Ensure, it's important that the GILState machinery knows about
it so it doesn't try to create another thread state for the thread (this is
a better fix for SF bug #1010677 than the first one attempted).
*/
static void
_PyGILState_NoteThreadState(struct _gilstate_runtime_state *gilstate, PyThreadState* tstate)
{
/* If autoTSSkey isn't initialized, this must be the very first
threadstate created in Py_Initialize(). Don't do anything for now
(we'll be back here when _PyGILState_Init is called). */
if (!gilstate->autoInterpreterState) {
return;
}
/* Stick the thread state for this thread in thread specific storage.
The only situation where you can legitimately have more than one
thread state for an OS level thread is when there are multiple
interpreters.
You shouldn't really be using the PyGILState_ APIs anyway (see issues
#10915 and #15751).
The first thread state created for that given OS level thread will
"win", which seems reasonable behaviour.
*/
if (PyThread_tss_get(&gilstate->autoTSSkey) == NULL) {
if ((PyThread_tss_set(&gilstate->autoTSSkey, (void *)tstate)) != 0) {
Py_FatalError("Couldn't create autoTSSkey mapping");
}
}
/* PyGILState_Release must not try to delete this thread state. */
tstate->gilstate_counter = 1;
}
/* The public functions */
static PyThreadState *
_PyGILState_GetThisThreadState(struct _gilstate_runtime_state *gilstate)
{
if (gilstate->autoInterpreterState == NULL)
return NULL;
return (PyThreadState *)PyThread_tss_get(&gilstate->autoTSSkey);
}
PyThreadState *
PyGILState_GetThisThreadState(void)
{
return _PyGILState_GetThisThreadState(&_PyRuntime.gilstate);
_PyRuntimeState *runtime = &_PyRuntime;
if (!current_tss_initialized(runtime)) {
return NULL;
}
return current_tss_get(runtime);
}
int
PyGILState_Check(void)
{
struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate;
if (!gilstate->check_enabled) {
_PyRuntimeState *runtime = &_PyRuntime;
if (!runtime->gilstate.check_enabled) {
return 1;
}
if (!PyThread_tss_is_created(&gilstate->autoTSSkey)) {
if (!current_tss_initialized(runtime)) {
return 1;
}
PyThreadState *tstate = _PyRuntimeGILState_GetThreadState(gilstate);
PyThreadState *tstate = current_fast_get(runtime);
if (tstate == NULL) {
return 0;
}
return (tstate == _PyGILState_GetThisThreadState(gilstate));
return (tstate == current_tss_get(runtime));
}
PyGILState_STATE
PyGILState_Ensure(void)
{
_PyRuntimeState *runtime = &_PyRuntime;
struct _gilstate_runtime_state *gilstate = &runtime->gilstate;
/* Note that we do not auto-init Python here - apart from
potential races with 2 threads auto-initializing, pep-311
@ -1699,27 +1823,29 @@ PyGILState_Ensure(void)
/* Ensure that _PyEval_InitThreads() and _PyGILState_Init() have been
called by Py_Initialize() */
assert(_PyEval_ThreadsInitialized(runtime));
assert(gilstate->autoInterpreterState);
assert(current_tss_initialized(runtime));
assert(runtime->gilstate.autoInterpreterState != NULL);
PyThreadState *tcur = (PyThreadState *)PyThread_tss_get(&gilstate->autoTSSkey);
int current;
PyThreadState *tcur = current_tss_get(runtime);
int has_gil;
if (tcur == NULL) {
/* Create a new Python thread state for this thread */
tcur = PyThreadState_New(gilstate->autoInterpreterState);
tcur = PyThreadState_New(runtime->gilstate.autoInterpreterState);
if (tcur == NULL) {
Py_FatalError("Couldn't create thread-state for new thread");
}
/* This is our thread state! We'll need to delete it in the
matching call to PyGILState_Release(). */
assert(tcur->gilstate_counter == 1);
tcur->gilstate_counter = 0;
current = 0; /* new thread state is never current */
has_gil = 0; /* new thread state is never current */
}
else {
current = PyThreadState_IsCurrent(tcur);
has_gil = holds_gil(tcur);
}
if (current == 0) {
if (!has_gil) {
PyEval_RestoreThread(tcur);
}
@ -1730,14 +1856,14 @@ PyGILState_Ensure(void)
*/
++tcur->gilstate_counter;
return current ? PyGILState_LOCKED : PyGILState_UNLOCKED;
return has_gil ? PyGILState_LOCKED : PyGILState_UNLOCKED;
}
void
PyGILState_Release(PyGILState_STATE oldstate)
{
_PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *tstate = PyThread_tss_get(&runtime->gilstate.autoTSSkey);
PyThreadState *tstate = current_tss_get(runtime);
if (tstate == NULL) {
Py_FatalError("auto-releasing thread-state, "
"but no thread-state for this thread");
@ -1748,12 +1874,12 @@ PyGILState_Release(PyGILState_STATE oldstate)
but while this is very new (April 2003), the extra check
by release-only users can't hurt.
*/
if (!PyThreadState_IsCurrent(tstate)) {
if (!holds_gil(tstate)) {
_Py_FatalErrorFormat(__func__,
"thread state %p must be current when releasing",
tstate);
}
assert(PyThreadState_IsCurrent(tstate));
assert(holds_gil(tstate));
--tstate->gilstate_counter;
assert(tstate->gilstate_counter >= 0); /* illegal counter value */
@ -1769,13 +1895,14 @@ PyGILState_Release(PyGILState_STATE oldstate)
* races; see bugs 225673 and 1061968 (that nasty bug has a
* habit of coming back).
*/
assert(_PyRuntimeGILState_GetThreadState(&runtime->gilstate) == tstate);
assert(current_fast_get(runtime) == tstate);
_PyThreadState_DeleteCurrent(tstate);
}
/* Release the lock if necessary */
else if (oldstate == PyGILState_UNLOCKED)
else if (oldstate == PyGILState_UNLOCKED) {
PyEval_SaveThread();
}
}
/**************************/
@ -1905,7 +2032,8 @@ _PyObject_CheckCrossInterpreterData(PyObject *obj)
int
_PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
{
PyThreadState *tstate = _PyThreadState_GET();
_PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *tstate = current_fast_get(runtime);
#ifdef Py_DEBUG
// The caller must hold the GIL
_Py_EnsureTstateNotNULL(tstate);
@ -1948,19 +2076,19 @@ _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *data)
typedef void (*releasefunc)(PyInterpreterState *, void *);
static void
_call_in_interpreter(struct _gilstate_runtime_state *gilstate,
PyInterpreterState *interp, releasefunc func, void *arg)
_call_in_interpreter(PyInterpreterState *interp, releasefunc func, void *arg)
{
/* We would use Py_AddPendingCall() if it weren't specific to the
* main interpreter (see bpo-33608). In the meantime we take a
* naive approach.
*/
_PyRuntimeState *runtime = interp->runtime;
PyThreadState *save_tstate = NULL;
if (interp != _PyRuntimeGILState_GetThreadState(gilstate)->interp) {
if (interp != current_fast_get(runtime)->interp) {
// XXX Using the "head" thread isn't strictly correct.
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
// XXX Possible GILState issues?
save_tstate = _PyThreadState_Swap(gilstate, tstate);
save_tstate = _PyThreadState_Swap(runtime, tstate);
}
// XXX Once the GIL is per-interpreter, this should be called with the
@ -1969,7 +2097,7 @@ _call_in_interpreter(struct _gilstate_runtime_state *gilstate,
// Switch back.
if (save_tstate != NULL) {
_PyThreadState_Swap(gilstate, save_tstate);
_PyThreadState_Swap(runtime, save_tstate);
}
}
@ -1993,8 +2121,7 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
}
// "Release" the data and/or the object.
struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate;
_call_in_interpreter(gilstate, interp,
_call_in_interpreter(interp,
(releasefunc)_PyCrossInterpreterData_Clear, data);
return 0;
}
@ -2314,8 +2441,9 @@ _PyInterpreterState_GetConfigCopy(PyConfig *config)
const PyConfig*
_Py_GetConfig(void)
{
_PyRuntimeState *runtime = &_PyRuntime;
assert(PyGILState_Check());
PyThreadState *tstate = _PyThreadState_GET();
PyThreadState *tstate = current_fast_get(runtime);
_Py_EnsureTstateNotNULL(tstate);
return _PyInterpreterState_GetConfig(tstate->interp);
}