Skip to content

Commit 6036c3e

Browse files
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 #59956
1 parent 8a2d4f4 commit 6036c3e

10 files changed

+373
-250
lines changed

Include/cpython/pystate.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,7 @@ struct _ts {
114114
PyThreadState *next;
115115
PyInterpreterState *interp;
116116

117-
/* Has been initialized to a safe state.
118-
119-
In order to be effective, this must be set to 0 during or right
120-
after allocation. */
121-
int _initialized;
117+
int _status;
122118

123119
int py_recursion_remaining;
124120
int py_recursion_limit;

Include/internal/pycore_pylifecycle.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ extern void _PyThread_FiniType(PyInterpreterState *interp);
6969
extern void _Py_Deepfreeze_Fini(void);
7070
extern void _PyArg_Fini(void);
7171

72-
extern PyStatus _PyGILState_Init(_PyRuntimeState *runtime);
72+
extern PyStatus _PyGILState_Init(PyInterpreterState *interp);
7373
extern PyStatus _PyGILState_SetTstate(PyThreadState *tstate);
7474
extern void _PyGILState_Fini(PyInterpreterState *interp);
7575

Include/internal/pycore_pystate.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ _Py_ThreadCanHandlePendingCalls(void)
6767
static inline PyThreadState*
6868
_PyRuntimeState_GetThreadState(_PyRuntimeState *runtime)
6969
{
70-
return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->gilstate.tstate_current);
70+
return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->tstate_current);
7171
}
7272

7373
/* Get the current Python thread state.
7474
75-
Efficient macro reading directly the 'gilstate.tstate_current' atomic
75+
Efficient macro reading directly the 'tstate_current' atomic
7676
variable. The macro is unsafe: it does not check for error and it can
7777
return NULL.
7878
@@ -120,7 +120,7 @@ static inline PyInterpreterState* _PyInterpreterState_GET(void) {
120120

121121
// PyThreadState functions
122122

123-
PyAPI_FUNC(void) _PyThreadState_SetCurrent(PyThreadState *tstate);
123+
PyAPI_FUNC(void) _PyThreadState_Bind(PyThreadState *tstate);
124124
// We keep this around exclusively for stable ABI compatibility.
125125
PyAPI_FUNC(void) _PyThreadState_Init(
126126
PyThreadState *tstate);
@@ -139,17 +139,28 @@ _PyThreadState_UpdateTracingState(PyThreadState *tstate)
139139
}
140140

141141

142+
/* PyThreadState status */
143+
144+
#define PyThreadState_UNINITIALIZED 0
145+
/* Has been initialized to a safe state.
146+
147+
In order to be effective, this must be set to 0 during or right
148+
after allocation. */
149+
#define PyThreadState_INITIALIZED 1
150+
#define PyThreadState_BOUND 2
151+
#define PyThreadState_UNBOUND 3
152+
153+
142154
/* Other */
143155

144156
PyAPI_FUNC(PyThreadState *) _PyThreadState_Swap(
145-
struct _gilstate_runtime_state *gilstate,
157+
_PyRuntimeState *runtime,
146158
PyThreadState *newts);
147159

148160
PyAPI_FUNC(PyStatus) _PyInterpreterState_Enable(_PyRuntimeState *runtime);
149161

150162
#ifdef HAVE_FORK
151163
extern PyStatus _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime);
152-
extern PyStatus _PyGILState_Reinit(_PyRuntimeState *runtime);
153164
extern void _PySignal_AfterFork(void);
154165
#endif
155166

Include/internal/pycore_runtime.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,11 @@ struct _gilstate_runtime_state {
4141
/* bpo-26558: Flag to disable PyGILState_Check().
4242
If set to non-zero, PyGILState_Check() always return 1. */
4343
int check_enabled;
44-
/* Assuming the current thread holds the GIL, this is the
45-
PyThreadState for the current thread. */
46-
_Py_atomic_address tstate_current;
4744
/* The single PyInterpreterState used by this process'
4845
GILState implementation
4946
*/
5047
/* TODO: Given interp_main, it may be possible to kill this ref */
5148
PyInterpreterState *autoInterpreterState;
52-
Py_tss_t autoTSSkey;
5349
};
5450

5551
/* Runtime audit hook state */
@@ -124,6 +120,12 @@ typedef struct pyruntimestate {
124120

125121
unsigned long main_thread;
126122

123+
/* Assuming the current thread holds the GIL, this is the
124+
PyThreadState for the current thread. */
125+
_Py_atomic_address tstate_current;
126+
/* Used for the thread state bound to the current thread. */
127+
Py_tss_t autoTSSkey;
128+
127129
PyWideStringList orig_argv;
128130

129131
struct _parser_runtime_state parser;

Include/internal/pycore_runtime_init.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ extern "C" {
3333
until _PyInterpreterState_Enable() is called. */ \
3434
.next_id = -1, \
3535
}, \
36+
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \
37+
in accordance with the specification. */ \
38+
.autoTSSkey = Py_tss_NEEDS_INIT, \
3639
.parser = _parser_runtime_state_INIT, \
3740
.imports = { \
3841
.lock = { \
@@ -49,9 +52,6 @@ extern "C" {
4952
}, \
5053
.gilstate = { \
5154
.check_enabled = 1, \
52-
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \
53-
in accordance with the specification. */ \
54-
.autoTSSkey = Py_tss_NEEDS_INIT, \
5555
}, \
5656
.dtoa = _dtoa_runtime_state_INIT(runtime), \
5757
.fileutils = { \

Modules/_threadmodule.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,13 +1074,7 @@ thread_run(void *boot_raw)
10741074
PyThreadState *tstate;
10751075

10761076
tstate = boot->tstate;
1077-
tstate->thread_id = PyThread_get_thread_ident();
1078-
#ifdef PY_HAVE_THREAD_NATIVE_ID
1079-
tstate->native_thread_id = PyThread_get_thread_native_id();
1080-
#else
1081-
tstate->native_thread_id = 0;
1082-
#endif
1083-
_PyThreadState_SetCurrent(tstate);
1077+
_PyThreadState_Bind(tstate);
10841078
PyEval_AcquireThread(tstate);
10851079
tstate->interp->threads.count++;
10861080

Modules/posixmodule.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ PyOS_AfterFork_Child(void)
587587
PyStatus status;
588588
_PyRuntimeState *runtime = &_PyRuntime;
589589

590-
status = _PyGILState_Reinit(runtime);
590+
status = _PyRuntimeState_ReInitThreads(runtime);
591591
if (_PyStatus_EXCEPTION(status)) {
592592
goto fatal_error;
593593
}
@@ -611,11 +611,6 @@ PyOS_AfterFork_Child(void)
611611

612612
_PySignal_AfterFork();
613613

614-
status = _PyRuntimeState_ReInitThreads(runtime);
615-
if (_PyStatus_EXCEPTION(status)) {
616-
goto fatal_error;
617-
}
618-
619614
status = _PyInterpreterState_DeleteExceptMain(runtime);
620615
if (_PyStatus_EXCEPTION(status)) {
621616
goto fatal_error;

Python/ceval_gil.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,7 @@ PyEval_AcquireThread(PyThreadState *tstate)
581581

582582
take_gil(tstate);
583583

584-
struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
585-
if (_PyThreadState_Swap(gilstate, tstate) != NULL) {
584+
if (_PyThreadState_Swap(tstate->interp->runtime, tstate) != NULL) {
586585
Py_FatalError("non-NULL old thread state");
587586
}
588587
}
@@ -593,7 +592,7 @@ PyEval_ReleaseThread(PyThreadState *tstate)
593592
assert(is_tstate_valid(tstate));
594593

595594
_PyRuntimeState *runtime = tstate->interp->runtime;
596-
PyThreadState *new_tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
595+
PyThreadState *new_tstate = _PyThreadState_Swap(runtime, NULL);
597596
if (new_tstate != tstate) {
598597
Py_FatalError("wrong thread state");
599598
}
@@ -643,7 +642,7 @@ PyThreadState *
643642
PyEval_SaveThread(void)
644643
{
645644
_PyRuntimeState *runtime = &_PyRuntime;
646-
PyThreadState *tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
645+
PyThreadState *tstate = _PyThreadState_Swap(runtime, NULL);
647646
_Py_EnsureTstateNotNULL(tstate);
648647

649648
struct _ceval_runtime_state *ceval = &runtime->ceval;
@@ -660,8 +659,7 @@ PyEval_RestoreThread(PyThreadState *tstate)
660659

661660
take_gil(tstate);
662661

663-
struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
664-
_PyThreadState_Swap(gilstate, tstate);
662+
_PyThreadState_Swap(tstate->interp->runtime, tstate);
665663
}
666664

667665

@@ -965,7 +963,7 @@ _Py_HandlePending(PyThreadState *tstate)
965963
/* GIL drop request */
966964
if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->gil_drop_request)) {
967965
/* Give another thread a chance */
968-
if (_PyThreadState_Swap(&runtime->gilstate, NULL) != tstate) {
966+
if (_PyThreadState_Swap(runtime, NULL) != tstate) {
969967
Py_FatalError("tstate mix-up");
970968
}
971969
drop_gil(ceval, interp_ceval_state, tstate);
@@ -974,7 +972,7 @@ _Py_HandlePending(PyThreadState *tstate)
974972

975973
take_gil(tstate);
976974

977-
if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) {
975+
if (_PyThreadState_Swap(runtime, tstate) != NULL) {
978976
Py_FatalError("orphan tstate");
979977
}
980978
}

Python/pylifecycle.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -675,12 +675,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
675675
const PyConfig *src_config,
676676
PyThreadState **tstate_p)
677677
{
678-
/* Auto-thread-state API */
679-
PyStatus status = _PyGILState_Init(runtime);
680-
if (_PyStatus_EXCEPTION(status)) {
681-
return status;
682-
}
683-
678+
PyStatus status;
684679
PyInterpreterState *interp = PyInterpreterState_New();
685680
if (interp == NULL) {
686681
return _PyStatus_ERR("can't make main interpreter");
@@ -692,6 +687,12 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
692687
return status;
693688
}
694689

690+
/* Auto-thread-state API */
691+
status = _PyGILState_Init(interp);
692+
if (_PyStatus_EXCEPTION(status)) {
693+
return status;
694+
}
695+
695696
const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
696697
init_interp_settings(interp, &config);
697698

@@ -1795,10 +1796,8 @@ finalize_interp_clear(PyThreadState *tstate)
17951796
static void
17961797
finalize_interp_delete(PyInterpreterState *interp)
17971798
{
1798-
if (_Py_IsMainInterpreter(interp)) {
1799-
/* Cleanup auto-thread-state */
1800-
_PyGILState_Fini(interp);
1801-
}
1799+
/* Cleanup auto-thread-state */
1800+
_PyGILState_Fini(interp);
18021801

18031802
/* We can't call _PyEval_FiniGIL() here because destroying the GIL lock can
18041803
fail when it is being awaited by another running daemon thread (see

0 commit comments

Comments
 (0)