mirror of https://github.com/python/cpython
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
This commit is contained in:
parent
8262c96bcc
commit
313f92a57b
|
@ -238,7 +238,19 @@ struct type_cache {
|
||||||
struct _is {
|
struct _is {
|
||||||
|
|
||||||
struct _is *next;
|
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
|
/* Reference to the _PyRuntime global variable. This field exists
|
||||||
to not have to pass runtime in addition to tstate to a function.
|
to not have to pass runtime in addition to tstate to a function.
|
||||||
|
@ -268,14 +280,6 @@ struct _is {
|
||||||
// (-1: "off", 1: "on", 0: no override)
|
// (-1: "off", 1: "on", 0: no override)
|
||||||
int override_frozen_modules;
|
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_path;
|
||||||
PyObject *codec_search_cache;
|
PyObject *codec_search_cache;
|
||||||
PyObject *codec_error_registry;
|
PyObject *codec_error_registry;
|
||||||
|
@ -302,8 +306,6 @@ struct _is {
|
||||||
PyObject *after_forkers_child;
|
PyObject *after_forkers_child;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint64_t tstate_next_unique_id;
|
|
||||||
|
|
||||||
struct _warnings_runtime_state warnings;
|
struct _warnings_runtime_state warnings;
|
||||||
struct atexit_state atexit;
|
struct atexit_state atexit;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
/* Interface to Sjoerd's portable C thread library */
|
/* Interface to Sjoerd's portable C thread library */
|
||||||
|
|
||||||
#include "Python.h"
|
#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_moduleobject.h" // _PyModule_GetState()
|
||||||
#include "pycore_pylifecycle.h"
|
#include "pycore_pylifecycle.h"
|
||||||
#include "pycore_pystate.h" // _PyThreadState_Init()
|
#include "pycore_pystate.h" // _PyThreadState_Init()
|
||||||
|
@ -1089,7 +1089,7 @@ thread_run(void *boot_raw)
|
||||||
#endif
|
#endif
|
||||||
_PyThreadState_Init(tstate);
|
_PyThreadState_Init(tstate);
|
||||||
PyEval_AcquireThread(tstate);
|
PyEval_AcquireThread(tstate);
|
||||||
tstate->interp->num_threads++;
|
tstate->interp->threads.count++;
|
||||||
|
|
||||||
PyObject *res = PyObject_Call(boot->func, boot->args, boot->kwargs);
|
PyObject *res = PyObject_Call(boot->func, boot->args, boot->kwargs);
|
||||||
if (res == NULL) {
|
if (res == NULL) {
|
||||||
|
@ -1105,7 +1105,7 @@ thread_run(void *boot_raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_bootstate_free(boot);
|
thread_bootstate_free(boot);
|
||||||
tstate->interp->num_threads--;
|
tstate->interp->threads.count--;
|
||||||
PyThreadState_Clear(tstate);
|
PyThreadState_Clear(tstate);
|
||||||
_PyThreadState_DeleteCurrent(tstate);
|
_PyThreadState_DeleteCurrent(tstate);
|
||||||
|
|
||||||
|
@ -1279,7 +1279,7 @@ static PyObject *
|
||||||
thread__count(PyObject *self, PyObject *Py_UNUSED(ignored))
|
thread__count(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
return PyLong_FromLong(interp->num_threads);
|
return PyLong_FromLong(interp->threads.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(_count_doc,
|
PyDoc_STRVAR(_count_doc,
|
||||||
|
|
|
@ -784,7 +784,7 @@ Py_SetRecursionLimit(int new_limit)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
interp->ceval.recursion_limit = new_limit;
|
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;
|
int depth = p->recursion_limit - p->recursion_remaining;
|
||||||
p->recursion_limit = new_limit;
|
p->recursion_limit = new_limit;
|
||||||
p->recursion_remaining = new_limit - depth;
|
p->recursion_remaining = new_limit - depth;
|
||||||
|
|
|
@ -2043,7 +2043,7 @@ Py_EndInterpreter(PyThreadState *tstate)
|
||||||
|
|
||||||
_PyAtExit_Call(tstate->interp);
|
_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");
|
Py_FatalError("not the last thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -271,7 +271,7 @@ PyInterpreterState_New(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
interp->tstate_next_unique_id = 0;
|
interp->threads.next_unique_id = 0;
|
||||||
|
|
||||||
interp->audit_hooks = NULL;
|
interp->audit_hooks = NULL;
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
|
||||||
}
|
}
|
||||||
|
|
||||||
HEAD_LOCK(runtime);
|
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);
|
PyThreadState_Clear(p);
|
||||||
}
|
}
|
||||||
HEAD_UNLOCK(runtime);
|
HEAD_UNLOCK(runtime);
|
||||||
|
@ -371,7 +371,7 @@ zapthreads(PyInterpreterState *interp, int check_current)
|
||||||
PyThreadState *tstate;
|
PyThreadState *tstate;
|
||||||
/* No need to lock the mutex here because this should only happen
|
/* No need to lock the mutex here because this should only happen
|
||||||
when the threads are all really dead (XXX famous last words). */
|
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);
|
_PyThreadState_Delete(tstate, check_current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,7 +399,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (interp->tstate_head != NULL) {
|
if (interp->threads.head != NULL) {
|
||||||
Py_FatalError("remaining threads");
|
Py_FatalError("remaining threads");
|
||||||
}
|
}
|
||||||
*p = interp->next;
|
*p = interp->next;
|
||||||
|
@ -702,12 +702,12 @@ new_threadstate(PyInterpreterState *interp, int init)
|
||||||
}
|
}
|
||||||
|
|
||||||
HEAD_LOCK(runtime);
|
HEAD_LOCK(runtime);
|
||||||
tstate->id = ++interp->tstate_next_unique_id;
|
tstate->id = ++interp->threads.next_unique_id;
|
||||||
tstate->prev = NULL;
|
tstate->prev = NULL;
|
||||||
tstate->next = interp->tstate_head;
|
tstate->next = interp->threads.head;
|
||||||
if (tstate->next)
|
if (tstate->next)
|
||||||
tstate->next->prev = tstate;
|
tstate->next->prev = tstate;
|
||||||
interp->tstate_head = tstate;
|
interp->threads.head = tstate;
|
||||||
HEAD_UNLOCK(runtime);
|
HEAD_UNLOCK(runtime);
|
||||||
|
|
||||||
return tstate;
|
return tstate;
|
||||||
|
@ -930,7 +930,7 @@ tstate_delete_common(PyThreadState *tstate,
|
||||||
tstate->prev->next = tstate->next;
|
tstate->prev->next = tstate->next;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
interp->tstate_head = tstate->next;
|
interp->threads.head = tstate->next;
|
||||||
}
|
}
|
||||||
if (tstate->next) {
|
if (tstate->next) {
|
||||||
tstate->next->prev = tstate->prev;
|
tstate->next->prev = tstate->prev;
|
||||||
|
@ -1008,7 +1008,7 @@ _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate)
|
||||||
/* Remove all thread states, except tstate, from the linked list of
|
/* Remove all thread states, except tstate, from the linked list of
|
||||||
thread states. This will allow calling PyThreadState_Clear()
|
thread states. This will allow calling PyThreadState_Clear()
|
||||||
without holding the lock. */
|
without holding the lock. */
|
||||||
PyThreadState *list = interp->tstate_head;
|
PyThreadState *list = interp->threads.head;
|
||||||
if (list == tstate) {
|
if (list == tstate) {
|
||||||
list = tstate->next;
|
list = tstate->next;
|
||||||
}
|
}
|
||||||
|
@ -1019,7 +1019,7 @@ _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate)
|
||||||
tstate->next->prev = tstate->prev;
|
tstate->next->prev = tstate->prev;
|
||||||
}
|
}
|
||||||
tstate->prev = tstate->next = NULL;
|
tstate->prev = tstate->next = NULL;
|
||||||
interp->tstate_head = tstate;
|
interp->threads.head = tstate;
|
||||||
HEAD_UNLOCK(runtime);
|
HEAD_UNLOCK(runtime);
|
||||||
|
|
||||||
/* Clear and deallocate all stale thread states. Even if this
|
/* Clear and deallocate all stale thread states. Even if this
|
||||||
|
@ -1180,7 +1180,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
|
||||||
* head_mutex for the duration.
|
* head_mutex for the duration.
|
||||||
*/
|
*/
|
||||||
HEAD_LOCK(runtime);
|
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) {
|
if (tstate->thread_id != id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1244,7 +1244,7 @@ PyInterpreterState_Next(PyInterpreterState *interp) {
|
||||||
|
|
||||||
PyThreadState *
|
PyThreadState *
|
||||||
PyInterpreterState_ThreadHead(PyInterpreterState *interp) {
|
PyInterpreterState_ThreadHead(PyInterpreterState *interp) {
|
||||||
return interp->tstate_head;
|
return interp->threads.head;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyThreadState *
|
PyThreadState *
|
||||||
|
@ -1281,7 +1281,7 @@ _PyThread_CurrentFrames(void)
|
||||||
PyInterpreterState *i;
|
PyInterpreterState *i;
|
||||||
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
|
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
|
||||||
PyThreadState *t;
|
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;
|
InterpreterFrame *frame = t->cframe->current_frame;
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1334,7 +1334,7 @@ _PyThread_CurrentExceptions(void)
|
||||||
PyInterpreterState *i;
|
PyInterpreterState *i;
|
||||||
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
|
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
|
||||||
PyThreadState *t;
|
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);
|
_PyErr_StackItem *err_info = _PyErr_GetTopmostException(t);
|
||||||
if (err_info == NULL) {
|
if (err_info == NULL) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -109,7 +109,7 @@ _PyThread_debug_deprecation(void)
|
||||||
size_t
|
size_t
|
||||||
PyThread_get_stacksize(void)
|
PyThread_get_stacksize(void)
|
||||||
{
|
{
|
||||||
return _PyInterpreterState_GET()->pythread_stacksize;
|
return _PyInterpreterState_GET()->threads.stacksize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only platforms defining a THREAD_SET_STACKSIZE() macro
|
/* Only platforms defining a THREAD_SET_STACKSIZE() macro
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "pycore_interp.h" // _PyInterpreterState.pythread_stacksize
|
#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize
|
||||||
|
|
||||||
/* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */
|
/* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */
|
||||||
/* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */
|
/* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */
|
||||||
|
@ -199,7 +199,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg)
|
||||||
obj->func = func;
|
obj->func = func;
|
||||||
obj->arg = arg;
|
obj->arg = arg;
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
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,
|
hThread = (HANDLE)_beginthreadex(0,
|
||||||
Py_SAFE_DOWNCAST(stacksize, Py_ssize_t, unsigned int),
|
Py_SAFE_DOWNCAST(stacksize, Py_ssize_t, unsigned int),
|
||||||
bootstrap, obj,
|
bootstrap, obj,
|
||||||
|
@ -376,13 +376,13 @@ _pythread_nt_set_stacksize(size_t size)
|
||||||
{
|
{
|
||||||
/* set to default */
|
/* set to default */
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
_PyInterpreterState_GET()->pythread_stacksize = 0;
|
_PyInterpreterState_GET()->threads.stacksize = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* valid range? */
|
/* valid range? */
|
||||||
if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
|
if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
|
||||||
_PyInterpreterState_GET()->pythread_stacksize = size;
|
_PyInterpreterState_GET()->threads.stacksize = size;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "pycore_interp.h" // _PyInterpreterState.pythread_stacksize
|
#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize
|
||||||
|
|
||||||
/* Posix threads interface */
|
/* Posix threads interface */
|
||||||
|
|
||||||
|
@ -262,7 +262,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg)
|
||||||
#endif
|
#endif
|
||||||
#if defined(THREAD_STACK_SIZE)
|
#if defined(THREAD_STACK_SIZE)
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
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;
|
tss = (stacksize != 0) ? stacksize : THREAD_STACK_SIZE;
|
||||||
if (tss != 0) {
|
if (tss != 0) {
|
||||||
if (pthread_attr_setstacksize(&attrs, tss) != 0) {
|
if (pthread_attr_setstacksize(&attrs, tss) != 0) {
|
||||||
|
@ -764,7 +764,7 @@ _pythread_pthread_set_stacksize(size_t size)
|
||||||
|
|
||||||
/* set to default */
|
/* set to default */
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
_PyInterpreterState_GET()->pythread_stacksize = 0;
|
_PyInterpreterState_GET()->threads.stacksize = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,7 +781,7 @@ _pythread_pthread_set_stacksize(size_t size)
|
||||||
rc = pthread_attr_setstacksize(&attrs, size);
|
rc = pthread_attr_setstacksize(&attrs, size);
|
||||||
pthread_attr_destroy(&attrs);
|
pthread_attr_destroy(&attrs);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
_PyInterpreterState_GET()->pythread_stacksize = size;
|
_PyInterpreterState_GET()->threads.stacksize = size;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue