Skip to content

Commit 313f92a

Browse files
bpo-46008: Move thread-related interpreter state into a sub-struct. (gh-29971)
This parallels _PyRuntimeState.interpreters. Doing this helps make it more clear what part of PyInterpreterState relates to its threads. https://bugs.python.org/issue46008
1 parent 8262c96 commit 313f92a

File tree

8 files changed

+42
-40
lines changed

8 files changed

+42
-40
lines changed

Include/internal/pycore_interp.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,19 @@ struct type_cache {
238238
struct _is {
239239

240240
struct _is *next;
241-
struct _ts *tstate_head;
241+
242+
struct pythreads {
243+
int _preallocated_used;
244+
uint64_t next_unique_id;
245+
struct _ts *head;
246+
/* Used in Modules/_threadmodule.c. */
247+
long count;
248+
/* Support for runtime thread stack size tuning.
249+
A value of 0 means using the platform's default stack size
250+
or the size specified by the THREAD_STACK_SIZE macro. */
251+
/* Used in Python/thread.c. */
252+
size_t stacksize;
253+
} threads;
242254

243255
/* Reference to the _PyRuntime global variable. This field exists
244256
to not have to pass runtime in addition to tstate to a function.
@@ -268,14 +280,6 @@ struct _is {
268280
// (-1: "off", 1: "on", 0: no override)
269281
int override_frozen_modules;
270282

271-
/* Used in Modules/_threadmodule.c. */
272-
long num_threads;
273-
/* Support for runtime thread stack size tuning.
274-
A value of 0 means using the platform's default stack size
275-
or the size specified by the THREAD_STACK_SIZE macro. */
276-
/* Used in Python/thread.c. */
277-
size_t pythread_stacksize;
278-
279283
PyObject *codec_search_path;
280284
PyObject *codec_search_cache;
281285
PyObject *codec_error_registry;
@@ -302,8 +306,6 @@ struct _is {
302306
PyObject *after_forkers_child;
303307
#endif
304308

305-
uint64_t tstate_next_unique_id;
306-
307309
struct _warnings_runtime_state warnings;
308310
struct atexit_state atexit;
309311

Modules/_threadmodule.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/* Interface to Sjoerd's portable C thread library */
44

55
#include "Python.h"
6-
#include "pycore_interp.h" // _PyInterpreterState.num_threads
6+
#include "pycore_interp.h" // _PyInterpreterState.threads.count
77
#include "pycore_moduleobject.h" // _PyModule_GetState()
88
#include "pycore_pylifecycle.h"
99
#include "pycore_pystate.h" // _PyThreadState_Init()
@@ -1089,7 +1089,7 @@ thread_run(void *boot_raw)
10891089
#endif
10901090
_PyThreadState_Init(tstate);
10911091
PyEval_AcquireThread(tstate);
1092-
tstate->interp->num_threads++;
1092+
tstate->interp->threads.count++;
10931093

10941094
PyObject *res = PyObject_Call(boot->func, boot->args, boot->kwargs);
10951095
if (res == NULL) {
@@ -1105,7 +1105,7 @@ thread_run(void *boot_raw)
11051105
}
11061106

11071107
thread_bootstate_free(boot);
1108-
tstate->interp->num_threads--;
1108+
tstate->interp->threads.count--;
11091109
PyThreadState_Clear(tstate);
11101110
_PyThreadState_DeleteCurrent(tstate);
11111111

@@ -1279,7 +1279,7 @@ static PyObject *
12791279
thread__count(PyObject *self, PyObject *Py_UNUSED(ignored))
12801280
{
12811281
PyInterpreterState *interp = _PyInterpreterState_GET();
1282-
return PyLong_FromLong(interp->num_threads);
1282+
return PyLong_FromLong(interp->threads.count);
12831283
}
12841284

12851285
PyDoc_STRVAR(_count_doc,

Python/ceval.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ Py_SetRecursionLimit(int new_limit)
784784
{
785785
PyInterpreterState *interp = _PyInterpreterState_GET();
786786
interp->ceval.recursion_limit = new_limit;
787-
for (PyThreadState *p = interp->tstate_head; p != NULL; p = p->next) {
787+
for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) {
788788
int depth = p->recursion_limit - p->recursion_remaining;
789789
p->recursion_limit = new_limit;
790790
p->recursion_remaining = new_limit - depth;

Python/pylifecycle.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2043,7 +2043,7 @@ Py_EndInterpreter(PyThreadState *tstate)
20432043

20442044
_PyAtExit_Call(tstate->interp);
20452045

2046-
if (tstate != interp->tstate_head || tstate->next != NULL) {
2046+
if (tstate != interp->threads.head || tstate->next != NULL) {
20472047
Py_FatalError("not the last thread");
20482048
}
20492049

Python/pystate.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ PyInterpreterState_New(void)
271271
return NULL;
272272
}
273273

274-
interp->tstate_next_unique_id = 0;
274+
interp->threads.next_unique_id = 0;
275275

276276
interp->audit_hooks = NULL;
277277

@@ -297,7 +297,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
297297
}
298298

299299
HEAD_LOCK(runtime);
300-
for (PyThreadState *p = interp->tstate_head; p != NULL; p = p->next) {
300+
for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) {
301301
PyThreadState_Clear(p);
302302
}
303303
HEAD_UNLOCK(runtime);
@@ -371,7 +371,7 @@ zapthreads(PyInterpreterState *interp, int check_current)
371371
PyThreadState *tstate;
372372
/* No need to lock the mutex here because this should only happen
373373
when the threads are all really dead (XXX famous last words). */
374-
while ((tstate = interp->tstate_head) != NULL) {
374+
while ((tstate = interp->threads.head) != NULL) {
375375
_PyThreadState_Delete(tstate, check_current);
376376
}
377377
}
@@ -399,7 +399,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
399399
break;
400400
}
401401
}
402-
if (interp->tstate_head != NULL) {
402+
if (interp->threads.head != NULL) {
403403
Py_FatalError("remaining threads");
404404
}
405405
*p = interp->next;
@@ -702,12 +702,12 @@ new_threadstate(PyInterpreterState *interp, int init)
702702
}
703703

704704
HEAD_LOCK(runtime);
705-
tstate->id = ++interp->tstate_next_unique_id;
705+
tstate->id = ++interp->threads.next_unique_id;
706706
tstate->prev = NULL;
707-
tstate->next = interp->tstate_head;
707+
tstate->next = interp->threads.head;
708708
if (tstate->next)
709709
tstate->next->prev = tstate;
710-
interp->tstate_head = tstate;
710+
interp->threads.head = tstate;
711711
HEAD_UNLOCK(runtime);
712712

713713
return tstate;
@@ -930,7 +930,7 @@ tstate_delete_common(PyThreadState *tstate,
930930
tstate->prev->next = tstate->next;
931931
}
932932
else {
933-
interp->tstate_head = tstate->next;
933+
interp->threads.head = tstate->next;
934934
}
935935
if (tstate->next) {
936936
tstate->next->prev = tstate->prev;
@@ -1008,7 +1008,7 @@ _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate)
10081008
/* Remove all thread states, except tstate, from the linked list of
10091009
thread states. This will allow calling PyThreadState_Clear()
10101010
without holding the lock. */
1011-
PyThreadState *list = interp->tstate_head;
1011+
PyThreadState *list = interp->threads.head;
10121012
if (list == tstate) {
10131013
list = tstate->next;
10141014
}
@@ -1019,7 +1019,7 @@ _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate)
10191019
tstate->next->prev = tstate->prev;
10201020
}
10211021
tstate->prev = tstate->next = NULL;
1022-
interp->tstate_head = tstate;
1022+
interp->threads.head = tstate;
10231023
HEAD_UNLOCK(runtime);
10241024

10251025
/* Clear and deallocate all stale thread states. Even if this
@@ -1180,7 +1180,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
11801180
* head_mutex for the duration.
11811181
*/
11821182
HEAD_LOCK(runtime);
1183-
for (PyThreadState *tstate = interp->tstate_head; tstate != NULL; tstate = tstate->next) {
1183+
for (PyThreadState *tstate = interp->threads.head; tstate != NULL; tstate = tstate->next) {
11841184
if (tstate->thread_id != id) {
11851185
continue;
11861186
}
@@ -1244,7 +1244,7 @@ PyInterpreterState_Next(PyInterpreterState *interp) {
12441244

12451245
PyThreadState *
12461246
PyInterpreterState_ThreadHead(PyInterpreterState *interp) {
1247-
return interp->tstate_head;
1247+
return interp->threads.head;
12481248
}
12491249

12501250
PyThreadState *
@@ -1281,7 +1281,7 @@ _PyThread_CurrentFrames(void)
12811281
PyInterpreterState *i;
12821282
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
12831283
PyThreadState *t;
1284-
for (t = i->tstate_head; t != NULL; t = t->next) {
1284+
for (t = i->threads.head; t != NULL; t = t->next) {
12851285
InterpreterFrame *frame = t->cframe->current_frame;
12861286
if (frame == NULL) {
12871287
continue;
@@ -1334,7 +1334,7 @@ _PyThread_CurrentExceptions(void)
13341334
PyInterpreterState *i;
13351335
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
13361336
PyThreadState *t;
1337-
for (t = i->tstate_head; t != NULL; t = t->next) {
1337+
for (t = i->threads.head; t != NULL; t = t->next) {
13381338
_PyErr_StackItem *err_info = _PyErr_GetTopmostException(t);
13391339
if (err_info == NULL) {
13401340
continue;

Python/thread.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ _PyThread_debug_deprecation(void)
109109
size_t
110110
PyThread_get_stacksize(void)
111111
{
112-
return _PyInterpreterState_GET()->pythread_stacksize;
112+
return _PyInterpreterState_GET()->threads.stacksize;
113113
}
114114

115115
/* Only platforms defining a THREAD_SET_STACKSIZE() macro

Python/thread_nt.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "pycore_interp.h" // _PyInterpreterState.pythread_stacksize
1+
#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize
22

33
/* This code implemented by [email protected] */
44
/* Fast NonRecursiveMutex support by Yakov Markovitch, [email protected] */
@@ -199,7 +199,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg)
199199
obj->func = func;
200200
obj->arg = arg;
201201
PyThreadState *tstate = _PyThreadState_GET();
202-
size_t stacksize = tstate ? tstate->interp->pythread_stacksize : 0;
202+
size_t stacksize = tstate ? tstate->interp->threads.stacksize : 0;
203203
hThread = (HANDLE)_beginthreadex(0,
204204
Py_SAFE_DOWNCAST(stacksize, Py_ssize_t, unsigned int),
205205
bootstrap, obj,
@@ -376,13 +376,13 @@ _pythread_nt_set_stacksize(size_t size)
376376
{
377377
/* set to default */
378378
if (size == 0) {
379-
_PyInterpreterState_GET()->pythread_stacksize = 0;
379+
_PyInterpreterState_GET()->threads.stacksize = 0;
380380
return 0;
381381
}
382382

383383
/* valid range? */
384384
if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
385-
_PyInterpreterState_GET()->pythread_stacksize = size;
385+
_PyInterpreterState_GET()->threads.stacksize = size;
386386
return 0;
387387
}
388388

Python/thread_pthread.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "pycore_interp.h" // _PyInterpreterState.pythread_stacksize
1+
#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize
22

33
/* Posix threads interface */
44

@@ -262,7 +262,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg)
262262
#endif
263263
#if defined(THREAD_STACK_SIZE)
264264
PyThreadState *tstate = _PyThreadState_GET();
265-
size_t stacksize = tstate ? tstate->interp->pythread_stacksize : 0;
265+
size_t stacksize = tstate ? tstate->interp->threads.stacksize : 0;
266266
tss = (stacksize != 0) ? stacksize : THREAD_STACK_SIZE;
267267
if (tss != 0) {
268268
if (pthread_attr_setstacksize(&attrs, tss) != 0) {
@@ -764,7 +764,7 @@ _pythread_pthread_set_stacksize(size_t size)
764764

765765
/* set to default */
766766
if (size == 0) {
767-
_PyInterpreterState_GET()->pythread_stacksize = 0;
767+
_PyInterpreterState_GET()->threads.stacksize = 0;
768768
return 0;
769769
}
770770

@@ -781,7 +781,7 @@ _pythread_pthread_set_stacksize(size_t size)
781781
rc = pthread_attr_setstacksize(&attrs, size);
782782
pthread_attr_destroy(&attrs);
783783
if (rc == 0) {
784-
_PyInterpreterState_GET()->pythread_stacksize = size;
784+
_PyInterpreterState_GET()->threads.stacksize = size;
785785
return 0;
786786
}
787787
}

0 commit comments

Comments
 (0)