Skip to content

Commit e042656

Browse files
committed
Improve NO_TSTATE_SENTINEL.
1 parent cad8786 commit e042656

1 file changed

Lines changed: 50 additions & 23 deletions

File tree

Python/pystate.c

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ to avoid the expense of doing their own locking).
6868
For each of these functions, the GIL must be held by the current thread.
6969
*/
7070

71+
static inline void
72+
ensure_tstate_is_valid(PyThreadState *tstate);
7173

7274
/* The attached thread state for the current thread. */
7375
_Py_thread_local PyThreadState *_Py_tss_tstate = NULL;
@@ -89,7 +91,7 @@ current_fast_get(void)
8991
static inline void
9092
current_fast_set(_PyRuntimeState *Py_UNUSED(runtime), PyThreadState *tstate)
9193
{
92-
assert(tstate != NULL);
94+
ensure_tstate_is_valid(tstate);
9395
_Py_tss_tstate = tstate;
9496
assert(tstate->interp != NULL);
9597
_Py_tss_interp = tstate->interp;
@@ -133,7 +135,7 @@ gilstate_get(void)
133135
static inline void
134136
gilstate_set(PyThreadState *tstate)
135137
{
136-
assert(tstate != NULL);
138+
ensure_tstate_is_valid(tstate);
137139
_Py_tss_gilstate = tstate;
138140
}
139141

@@ -162,7 +164,7 @@ static void tstate_mimalloc_bind(PyThreadState *);
162164
static void
163165
bind_tstate(PyThreadState *tstate)
164166
{
165-
assert(tstate != NULL);
167+
ensure_tstate_is_valid(tstate);
166168
assert(tstate_is_alive(tstate) && !tstate->_status.bound);
167169
assert(!tstate->_status.unbound); // just in case
168170
assert(!tstate->_status.bound_gilstate);
@@ -194,7 +196,7 @@ bind_tstate(PyThreadState *tstate)
194196
static void
195197
unbind_tstate(PyThreadState *tstate)
196198
{
197-
assert(tstate != NULL);
199+
ensure_tstate_is_valid(tstate);
198200
assert(tstate_is_bound(tstate));
199201
#ifndef HAVE_PTHREAD_STUBS
200202
assert(tstate->thread_id > 0);
@@ -235,7 +237,7 @@ unbind_tstate(PyThreadState *tstate)
235237
static void
236238
bind_gilstate_tstate(PyThreadState *tstate)
237239
{
238-
assert(tstate != NULL);
240+
ensure_tstate_is_valid(tstate);
239241
assert(tstate_is_alive(tstate));
240242
assert(tstate_is_bound(tstate));
241243
// XXX assert(!tstate->_status.active);
@@ -254,7 +256,7 @@ bind_gilstate_tstate(PyThreadState *tstate)
254256
static void
255257
unbind_gilstate_tstate(PyThreadState *tstate)
256258
{
257-
assert(tstate != NULL);
259+
ensure_tstate_is_valid(tstate);
258260
// XXX assert(tstate_is_alive(tstate));
259261
assert(tstate_is_bound(tstate));
260262
// XXX assert(!tstate->_status.active);
@@ -282,7 +284,7 @@ holds_gil(PyThreadState *tstate)
282284
{
283285
// XXX Fall back to tstate->interp->runtime->ceval.gil.last_holder
284286
// (and tstate->interp->runtime->ceval.gil.locked).
285-
assert(tstate != NULL);
287+
ensure_tstate_is_valid(tstate);
286288
/* Must be the tstate for this thread */
287289
assert(tstate == gilstate_get());
288290
return tstate == current_fast_get();
@@ -781,7 +783,7 @@ static void
781783
interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
782784
{
783785
assert(interp != NULL);
784-
assert(tstate != NULL);
786+
ensure_tstate_is_valid(tstate);
785787
_PyRuntimeState *runtime = interp->runtime;
786788

787789
/* XXX Conditions we need to enforce:
@@ -2009,7 +2011,7 @@ PyThreadState_DeleteCurrent(void)
20092011
PyThreadState *
20102012
_PyThreadState_RemoveExcept(PyThreadState *tstate)
20112013
{
2012-
assert(tstate != NULL);
2014+
ensure_tstate_is_valid(tstate);
20132015
PyInterpreterState *interp = tstate->interp;
20142016
_PyRuntimeState *runtime = interp->runtime;
20152017

@@ -2078,7 +2080,7 @@ _PyThreadState_DeleteList(PyThreadState *list, int is_after_fork)
20782080
PyObject *
20792081
_PyThreadState_GetDict(PyThreadState *tstate)
20802082
{
2081-
assert(tstate != NULL);
2083+
ensure_tstate_is_valid(tstate);
20822084
if (tstate->dict == NULL) {
20832085
tstate->dict = PyDict_New();
20842086
if (tstate->dict == NULL) {
@@ -2103,15 +2105,15 @@ PyThreadState_GetDict(void)
21032105
PyInterpreterState *
21042106
PyThreadState_GetInterpreter(PyThreadState *tstate)
21052107
{
2106-
assert(tstate != NULL);
2108+
ensure_tstate_is_valid(tstate);
21072109
return tstate->interp;
21082110
}
21092111

21102112

21112113
PyFrameObject*
21122114
PyThreadState_GetFrame(PyThreadState *tstate)
21132115
{
2114-
assert(tstate != NULL);
2116+
ensure_tstate_is_valid(tstate);
21152117
_PyInterpreterFrame *f = _PyThreadState_GetFrame(tstate);
21162118
if (f == NULL) {
21172119
return NULL;
@@ -2127,15 +2129,15 @@ PyThreadState_GetFrame(PyThreadState *tstate)
21272129
uint64_t
21282130
PyThreadState_GetID(PyThreadState *tstate)
21292131
{
2130-
assert(tstate != NULL);
2132+
ensure_tstate_is_valid(tstate);
21312133
return tstate->id;
21322134
}
21332135

21342136

21352137
static inline void
21362138
tstate_activate(PyThreadState *tstate)
21372139
{
2138-
assert(tstate != NULL);
2140+
ensure_tstate_is_valid(tstate);
21392141
// XXX assert(tstate_is_alive(tstate));
21402142
assert(tstate_is_bound(tstate));
21412143
assert(!tstate->_status.active);
@@ -2152,7 +2154,7 @@ tstate_activate(PyThreadState *tstate)
21522154
static inline void
21532155
tstate_deactivate(PyThreadState *tstate)
21542156
{
2155-
assert(tstate != NULL);
2157+
ensure_tstate_is_valid(tstate);
21562158
// XXX assert(tstate_is_alive(tstate));
21572159
assert(tstate_is_bound(tstate));
21582160
assert(tstate->_status.active);
@@ -2170,6 +2172,7 @@ tstate_deactivate(PyThreadState *tstate)
21702172
static int
21712173
tstate_try_attach(PyThreadState *tstate)
21722174
{
2175+
ensure_tstate_is_valid(tstate);
21732176
#ifdef Py_GIL_DISABLED
21742177
int expected = _Py_THREAD_DETACHED;
21752178
return _Py_atomic_compare_exchange_int(&tstate->state,
@@ -2185,6 +2188,7 @@ tstate_try_attach(PyThreadState *tstate)
21852188
static void
21862189
tstate_set_detached(PyThreadState *tstate, int detached_state)
21872190
{
2191+
ensure_tstate_is_valid(tstate);
21882192
assert(_Py_atomic_load_int_relaxed(&tstate->state) == _Py_THREAD_ATTACHED);
21892193
#ifdef Py_GIL_DISABLED
21902194
_Py_atomic_store_int(&tstate->state, detached_state);
@@ -2196,6 +2200,7 @@ tstate_set_detached(PyThreadState *tstate, int detached_state)
21962200
static void
21972201
tstate_wait_attach(PyThreadState *tstate)
21982202
{
2203+
ensure_tstate_is_valid(tstate);
21992204
do {
22002205
int state = _Py_atomic_load_int_relaxed(&tstate->state);
22012206
if (state == _Py_THREAD_SUSPENDED) {
@@ -2217,6 +2222,7 @@ tstate_wait_attach(PyThreadState *tstate)
22172222
void
22182223
_PyThreadState_Attach(PyThreadState *tstate)
22192224
{
2225+
ensure_tstate_is_valid(tstate);
22202226
#if defined(Py_DEBUG)
22212227
// This is called from PyEval_RestoreThread(). Similar
22222228
// to it, we need to ensure errno doesn't change.
@@ -2276,6 +2282,7 @@ _PyThreadState_Attach(PyThreadState *tstate)
22762282
static void
22772283
detach_thread(PyThreadState *tstate, int detached_state)
22782284
{
2285+
ensure_tstate_is_valid(tstate);
22792286
// XXX assert(tstate_is_alive(tstate) && tstate_is_bound(tstate));
22802287
assert(_Py_atomic_load_int_relaxed(&tstate->state) == _Py_THREAD_ATTACHED);
22812288
assert(tstate == current_fast_get());
@@ -2300,6 +2307,7 @@ _PyThreadState_Detach(PyThreadState *tstate)
23002307
void
23012308
_PyThreadState_Suspend(PyThreadState *tstate)
23022309
{
2310+
ensure_tstate_is_valid(tstate);
23032311
_PyRuntimeState *runtime = &_PyRuntime;
23042312

23052313
assert(_Py_atomic_load_int_relaxed(&tstate->state) == _Py_THREAD_ATTACHED);
@@ -2587,6 +2595,7 @@ PyThreadState_Get(void)
25872595
{
25882596
PyThreadState *tstate = current_fast_get();
25892597
_Py_EnsureTstateNotNULL(tstate);
2598+
ensure_tstate_is_valid(tstate);
25902599
return tstate;
25912600
}
25922601

@@ -2666,7 +2675,9 @@ PyInterpreterState_ThreadHead(PyInterpreterState *interp) {
26662675
}
26672676

26682677
PyThreadState *
2669-
PyThreadState_Next(PyThreadState *tstate) {
2678+
PyThreadState_Next(PyThreadState *tstate)
2679+
{
2680+
ensure_tstate_is_valid(tstate);
26702681
return tstate->next;
26712682
}
26722683

@@ -2841,7 +2852,7 @@ void
28412852
_PyGILState_SetTstate(PyThreadState *tstate)
28422853
{
28432854
/* must init with valid states */
2844-
assert(tstate != NULL);
2855+
ensure_tstate_is_valid(tstate);
28452856
assert(tstate->interp != NULL);
28462857

28472858
if (!_Py_IsMainInterpreter(tstate->interp)) {
@@ -3087,6 +3098,7 @@ _PyInterpreterState_HasFeature(PyInterpreterState *interp, unsigned long feature
30873098
static PyObject **
30883099
push_chunk(PyThreadState *tstate, int size)
30893100
{
3101+
ensure_tstate_is_valid(tstate);
30903102
int allocate_size = _PY_DATA_STACK_CHUNK_SIZE;
30913103
while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) {
30923104
allocate_size *= 2;
@@ -3123,6 +3135,7 @@ push_chunk(PyThreadState *tstate, int size)
31233135
_PyInterpreterFrame *
31243136
_PyThreadState_PushFrame(PyThreadState *tstate, size_t size)
31253137
{
3138+
ensure_tstate_is_valid(tstate);
31263139
assert(size < INT_MAX/sizeof(PyObject *));
31273140
if (_PyThreadState_HasStackSpace(tstate, (int)size)) {
31283141
_PyInterpreterFrame *res = (_PyInterpreterFrame *)tstate->datastack_top;
@@ -3135,6 +3148,7 @@ _PyThreadState_PushFrame(PyThreadState *tstate, size_t size)
31353148
void
31363149
_PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame * frame)
31373150
{
3151+
ensure_tstate_is_valid(tstate);
31383152
assert(tstate->datastack_chunk);
31393153
PyObject **base = (PyObject **)frame;
31403154
if (base == &tstate->datastack_chunk->data[0]) {
@@ -3171,6 +3185,7 @@ _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame * frame)
31713185
int
31723186
_PyThreadState_CheckConsistency(PyThreadState *tstate)
31733187
{
3188+
ensure_tstate_is_valid(tstate);
31743189
assert(!_PyMem_IsPtrFreed(tstate));
31753190
assert(!_PyMem_IsPtrFreed(tstate->interp));
31763191
return 1;
@@ -3189,13 +3204,15 @@ _PyThreadState_CheckConsistency(PyThreadState *tstate)
31893204
int
31903205
_PyThreadState_MustExit(PyThreadState *tstate)
31913206
{
3207+
ensure_tstate_is_valid(tstate);
31923208
int state = _Py_atomic_load_int_relaxed(&tstate->state);
31933209
return state == _Py_THREAD_SHUTTING_DOWN;
31943210
}
31953211

31963212
void
31973213
_PyThreadState_HangThread(PyThreadState *tstate)
31983214
{
3215+
ensure_tstate_is_valid(tstate);
31993216
_PyThreadStateImpl *tstate_impl = (_PyThreadStateImpl *)tstate;
32003217
decref_threadstate(tstate_impl);
32013218
PyThread_hang_thread();
@@ -3209,6 +3226,7 @@ static void
32093226
tstate_mimalloc_bind(PyThreadState *tstate)
32103227
{
32113228
#ifdef Py_GIL_DISABLED
3229+
ensure_tstate_is_valid(tstate);
32123230
struct _mimalloc_thread_state *mts = &((_PyThreadStateImpl*)tstate)->mimalloc;
32133231

32143232
// Initialize the mimalloc thread state. This must be called from the
@@ -3262,6 +3280,7 @@ void
32623280
_PyThreadState_ClearMimallocHeaps(PyThreadState *tstate)
32633281
{
32643282
#ifdef Py_GIL_DISABLED
3283+
ensure_tstate_is_valid(tstate);
32653284
if (!tstate->_status.bound) {
32663285
// The mimalloc heaps are only initialized when the thread is bound.
32673286
return;
@@ -3490,7 +3509,15 @@ PyInterpreterView_FromMain(void)
34903509
// thread state was attached.
34913510
// To do this, we just use the memory address of a global variable and
34923511
// cast it to a PyThreadState *.
3493-
static const int NO_TSTATE_SENTINEL = 0;
3512+
static const PyThreadState _no_tstate_sentinel = {0};
3513+
#define NO_TSTATE_SENTINEL ((PyThreadState *)&_no_tstate_sentinel)
3514+
3515+
static inline void
3516+
ensure_tstate_is_valid(PyThreadState *tstate)
3517+
{
3518+
assert(tstate != NULL);
3519+
assert(tstate != NO_TSTATE_SENTINEL);
3520+
}
34943521

34953522
PyThreadState *
34963523
PyThreadState_Ensure(PyInterpreterGuard *guard)
@@ -3502,7 +3529,7 @@ PyThreadState_Ensure(PyInterpreterGuard *guard)
35023529
if (attached_tstate != NULL && attached_tstate->interp == interp) {
35033530
/* Yay! We already have an attached thread state that matches. */
35043531
++attached_tstate->ensure.counter;
3505-
return (PyThreadState *)&NO_TSTATE_SENTINEL;
3532+
return NO_TSTATE_SENTINEL;
35063533
}
35073534

35083535
PyThreadState *detached_gilstate = gilstate_get();
@@ -3511,7 +3538,7 @@ PyThreadState_Ensure(PyInterpreterGuard *guard)
35113538
assert(attached_tstate == NULL);
35123539
++detached_gilstate->ensure.counter;
35133540
_PyThreadState_Attach(detached_gilstate);
3514-
return (PyThreadState *)&NO_TSTATE_SENTINEL;
3541+
return NO_TSTATE_SENTINEL;
35153542
}
35163543

35173544
PyThreadState *fresh_tstate = _PyThreadState_NewBound(interp,
@@ -3528,7 +3555,7 @@ PyThreadState_Ensure(PyInterpreterGuard *guard)
35283555
_PyThreadState_Attach(fresh_tstate);
35293556
}
35303557

3531-
return (PyThreadState *)&NO_TSTATE_SENTINEL;
3558+
return NO_TSTATE_SENTINEL;
35323559
}
35333560

35343561
PyThreadState *
@@ -3547,7 +3574,7 @@ PyThreadState_EnsureFromView(PyInterpreterView *view)
35473574
}
35483575

35493576
PyThreadState *tstate = current_fast_get();
3550-
assert(tstate != NULL);
3577+
ensure_tstate_is_valid(tstate);
35513578

35523579
if (tstate->ensure.owned_guard != NULL) {
35533580
assert(tstate->ensure.owned_guard->interp == guard->interp);
@@ -3575,7 +3602,7 @@ PyThreadState_Release(PyThreadState *old_tstate)
35753602
}
35763603

35773604
PyThreadState *to_restore;
3578-
if (old_tstate == (PyThreadState *)&NO_TSTATE_SENTINEL) {
3605+
if (old_tstate == NO_TSTATE_SENTINEL) {
35793606
to_restore = NULL;
35803607
}
35813608
else {

0 commit comments

Comments
 (0)