From 313f92a57bc3887026ec16adb536bb2b7580ce47 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 7 Dec 2021 14:03:47 -0700 Subject: 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 --- Include/internal/pycore_interp.h | 24 +++++++++++++----------- Modules/_threadmodule.c | 8 ++++---- Python/ceval.c | 2 +- Python/pylifecycle.c | 2 +- Python/pystate.c | 28 ++++++++++++++-------------- Python/thread.c | 2 +- Python/thread_nt.h | 8 ++++---- Python/thread_pthread.h | 8 ++++---- 8 files changed, 42 insertions(+), 40 deletions(-) diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index f52ee59..53938e3 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -238,7 +238,19 @@ struct type_cache { 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. @@ -268,14 +280,6 @@ struct _is { // (-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; @@ -302,8 +306,6 @@ struct _is { PyObject *after_forkers_child; #endif - uint64_t tstate_next_unique_id; - struct _warnings_runtime_state warnings; struct atexit_state atexit; diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 39b116a..2ba081d 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -3,7 +3,7 @@ /* 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() @@ -1089,7 +1089,7 @@ thread_run(void *boot_raw) #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) { @@ -1105,7 +1105,7 @@ thread_run(void *boot_raw) } thread_bootstate_free(boot); - tstate->interp->num_threads--; + tstate->interp->threads.count--; PyThreadState_Clear(tstate); _PyThreadState_DeleteCurrent(tstate); @@ -1279,7 +1279,7 @@ static PyObject * 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, diff --git a/Python/ceval.c b/Python/ceval.c index 36d1360..2e40c0f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -784,7 +784,7 @@ Py_SetRecursionLimit(int new_limit) { 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; diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 84b76ea..f648dda 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2043,7 +2043,7 @@ Py_EndInterpreter(PyThreadState *tstate) _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"); } diff --git a/Python/pystate.c b/Python/pystate.c index a0bd050..4dd4cab 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -271,7 +271,7 @@ PyInterpreterState_New(void) return NULL; } - interp->tstate_next_unique_id = 0; + interp->threads.next_unique_id = 0; interp->audit_hooks = NULL; @@ -297,7 +297,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) } 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); @@ -371,7 +371,7 @@ zapthreads(PyInterpreterState *interp, int check_current) 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); } } @@ -399,7 +399,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp) break; } } - if (interp->tstate_head != NULL) { + if (interp->threads.head != NULL) { Py_FatalError("remaining threads"); } *p = interp->next; @@ -702,12 +702,12 @@ new_threadstate(PyInterpreterState *interp, int init) } 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; @@ -930,7 +930,7 @@ tstate_delete_common(PyThreadState *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; @@ -1008,7 +1008,7 @@ _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate) /* 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; } @@ -1019,7 +1019,7 @@ _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate) 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 @@ -1180,7 +1180,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) * 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; } @@ -1244,7 +1244,7 @@ PyInterpreterState_Next(PyInterpreterState *interp) { PyThreadState * PyInterpreterState_ThreadHead(PyInterpreterState *interp) { - return interp->tstate_head; + return interp->threads.head; } PyThreadState * @@ -1281,7 +1281,7 @@ _PyThread_CurrentFrames(void) 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; @@ -1334,7 +1334,7 @@ _PyThread_CurrentExceptions(void) 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; diff --git a/Python/thread.c b/Python/thread.c index dfe28b6..b1c0cfe 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -109,7 +109,7 @@ _PyThread_debug_deprecation(void) size_t PyThread_get_stacksize(void) { - return _PyInterpreterState_GET()->pythread_stacksize; + return _PyInterpreterState_GET()->threads.stacksize; } /* Only platforms defining a THREAD_SET_STACKSIZE() macro diff --git a/Python/thread_nt.h b/Python/thread_nt.h index 0dde1a0..084bd58 100644 --- a/Python/thread_nt.h +++ b/Python/thread_nt.h @@ -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 */ /* 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->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, @@ -376,13 +376,13 @@ _pythread_nt_set_stacksize(size_t size) { /* 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; } diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 12dad7e..c90ab25 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -1,4 +1,4 @@ -#include "pycore_interp.h" // _PyInterpreterState.pythread_stacksize +#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize /* Posix threads interface */ @@ -262,7 +262,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) #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) { @@ -764,7 +764,7 @@ _pythread_pthread_set_stacksize(size_t size) /* set to default */ if (size == 0) { - _PyInterpreterState_GET()->pythread_stacksize = 0; + _PyInterpreterState_GET()->threads.stacksize = 0; return 0; } @@ -781,7 +781,7 @@ _pythread_pthread_set_stacksize(size_t size) 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; } } -- cgit v0.12