This parallels _PyRuntimeState.interpreters. Doing this helps make it more clear what part of PyInterpreterState relates to its threads.
https://bugs.python.org/issue46008
struct _is {
struct _is *next;
- struct _ts *tstate_head;
+
+ struct pythreads {
+ int _preallocated_used;
+ uint64_t next_unique_id;
+ struct _ts *head;
+ /* Used in Modules/_threadmodule.c. */
+ long count;
+ /* Support for runtime thread stack size tuning.
+ A value of 0 means using the platform's default stack size
+ or the size specified by the THREAD_STACK_SIZE macro. */
+ /* Used in Python/thread.c. */
+ size_t stacksize;
+ } threads;
/* Reference to the _PyRuntime global variable. This field exists
to not have to pass runtime in addition to tstate to a function.
// (-1: "off", 1: "on", 0: no override)
int override_frozen_modules;
- /* Used in Modules/_threadmodule.c. */
- long num_threads;
- /* Support for runtime thread stack size tuning.
- A value of 0 means using the platform's default stack size
- or the size specified by the THREAD_STACK_SIZE macro. */
- /* Used in Python/thread.c. */
- size_t pythread_stacksize;
-
PyObject *codec_search_path;
PyObject *codec_search_cache;
PyObject *codec_error_registry;
PyObject *after_forkers_child;
#endif
- uint64_t tstate_next_unique_id;
-
struct _warnings_runtime_state warnings;
struct atexit_state atexit;
/* Interface to Sjoerd's portable C thread library */
#include "Python.h"
-#include "pycore_interp.h" // _PyInterpreterState.num_threads
+#include "pycore_interp.h" // _PyInterpreterState.threads.count
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_pylifecycle.h"
#include "pycore_pystate.h" // _PyThreadState_Init()
#endif
_PyThreadState_Init(tstate);
PyEval_AcquireThread(tstate);
- tstate->interp->num_threads++;
+ tstate->interp->threads.count++;
PyObject *res = PyObject_Call(boot->func, boot->args, boot->kwargs);
if (res == NULL) {
}
thread_bootstate_free(boot);
- tstate->interp->num_threads--;
+ tstate->interp->threads.count--;
PyThreadState_Clear(tstate);
_PyThreadState_DeleteCurrent(tstate);
thread__count(PyObject *self, PyObject *Py_UNUSED(ignored))
{
PyInterpreterState *interp = _PyInterpreterState_GET();
- return PyLong_FromLong(interp->num_threads);
+ return PyLong_FromLong(interp->threads.count);
}
PyDoc_STRVAR(_count_doc,
{
PyInterpreterState *interp = _PyInterpreterState_GET();
interp->ceval.recursion_limit = new_limit;
- for (PyThreadState *p = interp->tstate_head; p != NULL; p = p->next) {
+ for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) {
int depth = p->recursion_limit - p->recursion_remaining;
p->recursion_limit = new_limit;
p->recursion_remaining = new_limit - depth;
_PyAtExit_Call(tstate->interp);
- if (tstate != interp->tstate_head || tstate->next != NULL) {
+ if (tstate != interp->threads.head || tstate->next != NULL) {
Py_FatalError("not the last thread");
}
return NULL;
}
- interp->tstate_next_unique_id = 0;
+ interp->threads.next_unique_id = 0;
interp->audit_hooks = NULL;
}
HEAD_LOCK(runtime);
- for (PyThreadState *p = interp->tstate_head; p != NULL; p = p->next) {
+ for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) {
PyThreadState_Clear(p);
}
HEAD_UNLOCK(runtime);
PyThreadState *tstate;
/* No need to lock the mutex here because this should only happen
when the threads are all really dead (XXX famous last words). */
- while ((tstate = interp->tstate_head) != NULL) {
+ while ((tstate = interp->threads.head) != NULL) {
_PyThreadState_Delete(tstate, check_current);
}
}
break;
}
}
- if (interp->tstate_head != NULL) {
+ if (interp->threads.head != NULL) {
Py_FatalError("remaining threads");
}
*p = interp->next;
}
HEAD_LOCK(runtime);
- tstate->id = ++interp->tstate_next_unique_id;
+ tstate->id = ++interp->threads.next_unique_id;
tstate->prev = NULL;
- tstate->next = interp->tstate_head;
+ tstate->next = interp->threads.head;
if (tstate->next)
tstate->next->prev = tstate;
- interp->tstate_head = tstate;
+ interp->threads.head = tstate;
HEAD_UNLOCK(runtime);
return tstate;
tstate->prev->next = tstate->next;
}
else {
- interp->tstate_head = tstate->next;
+ interp->threads.head = tstate->next;
}
if (tstate->next) {
tstate->next->prev = tstate->prev;
/* Remove all thread states, except tstate, from the linked list of
thread states. This will allow calling PyThreadState_Clear()
without holding the lock. */
- PyThreadState *list = interp->tstate_head;
+ PyThreadState *list = interp->threads.head;
if (list == tstate) {
list = tstate->next;
}
tstate->next->prev = tstate->prev;
}
tstate->prev = tstate->next = NULL;
- interp->tstate_head = tstate;
+ interp->threads.head = tstate;
HEAD_UNLOCK(runtime);
/* Clear and deallocate all stale thread states. Even if this
* head_mutex for the duration.
*/
HEAD_LOCK(runtime);
- for (PyThreadState *tstate = interp->tstate_head; tstate != NULL; tstate = tstate->next) {
+ for (PyThreadState *tstate = interp->threads.head; tstate != NULL; tstate = tstate->next) {
if (tstate->thread_id != id) {
continue;
}
PyThreadState *
PyInterpreterState_ThreadHead(PyInterpreterState *interp) {
- return interp->tstate_head;
+ return interp->threads.head;
}
PyThreadState *
PyInterpreterState *i;
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
PyThreadState *t;
- for (t = i->tstate_head; t != NULL; t = t->next) {
+ for (t = i->threads.head; t != NULL; t = t->next) {
InterpreterFrame *frame = t->cframe->current_frame;
if (frame == NULL) {
continue;
PyInterpreterState *i;
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
PyThreadState *t;
- for (t = i->tstate_head; t != NULL; t = t->next) {
+ for (t = i->threads.head; t != NULL; t = t->next) {
_PyErr_StackItem *err_info = _PyErr_GetTopmostException(t);
if (err_info == NULL) {
continue;
size_t
PyThread_get_stacksize(void)
{
- return _PyInterpreterState_GET()->pythread_stacksize;
+ return _PyInterpreterState_GET()->threads.stacksize;
}
/* Only platforms defining a THREAD_SET_STACKSIZE() macro
-#include "pycore_interp.h" // _PyInterpreterState.pythread_stacksize
+#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize
/* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */
/* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */
obj->func = func;
obj->arg = arg;
PyThreadState *tstate = _PyThreadState_GET();
- size_t stacksize = tstate ? tstate->interp->pythread_stacksize : 0;
+ size_t stacksize = tstate ? tstate->interp->threads.stacksize : 0;
hThread = (HANDLE)_beginthreadex(0,
Py_SAFE_DOWNCAST(stacksize, Py_ssize_t, unsigned int),
bootstrap, obj,
{
/* set to default */
if (size == 0) {
- _PyInterpreterState_GET()->pythread_stacksize = 0;
+ _PyInterpreterState_GET()->threads.stacksize = 0;
return 0;
}
/* valid range? */
if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
- _PyInterpreterState_GET()->pythread_stacksize = size;
+ _PyInterpreterState_GET()->threads.stacksize = size;
return 0;
}
-#include "pycore_interp.h" // _PyInterpreterState.pythread_stacksize
+#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize
/* Posix threads interface */
#endif
#if defined(THREAD_STACK_SIZE)
PyThreadState *tstate = _PyThreadState_GET();
- size_t stacksize = tstate ? tstate->interp->pythread_stacksize : 0;
+ size_t stacksize = tstate ? tstate->interp->threads.stacksize : 0;
tss = (stacksize != 0) ? stacksize : THREAD_STACK_SIZE;
if (tss != 0) {
if (pthread_attr_setstacksize(&attrs, tss) != 0) {
/* set to default */
if (size == 0) {
- _PyInterpreterState_GET()->pythread_stacksize = 0;
+ _PyInterpreterState_GET()->threads.stacksize = 0;
return 0;
}
rc = pthread_attr_setstacksize(&attrs, size);
pthread_attr_destroy(&attrs);
if (rc == 0) {
- _PyInterpreterState_GET()->pythread_stacksize = size;
+ _PyInterpreterState_GET()->threads.stacksize = size;
return 0;
}
}