Skip to content

bpo-46008: Move thread-related interpreter state into a sub-struct. #29971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down
8 changes: 4 additions & 4 deletions Modules/_threadmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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) {
Expand All @@ -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);

Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,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;
Expand Down
2 changes: 1 addition & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand Down
28 changes: 14 additions & 14 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ PyInterpreterState_New(void)
return NULL;
}

interp->tstate_next_unique_id = 0;
interp->threads.next_unique_id = 0;

interp->audit_hooks = NULL;

Expand All @@ -295,7 +295,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);
Expand Down Expand Up @@ -369,7 +369,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);
}
}
Expand Down Expand Up @@ -397,7 +397,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
break;
}
}
if (interp->tstate_head != NULL) {
if (interp->threads.head != NULL) {
Py_FatalError("remaining threads");
}
*p = interp->next;
Expand Down Expand Up @@ -700,12 +700,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;
Expand Down Expand Up @@ -928,7 +928,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;
Expand Down Expand Up @@ -1006,7 +1006,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;
}
Expand All @@ -1017,7 +1017,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
Expand Down Expand Up @@ -1178,7 +1178,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;
}
Expand Down Expand Up @@ -1242,7 +1242,7 @@ PyInterpreterState_Next(PyInterpreterState *interp) {

PyThreadState *
PyInterpreterState_ThreadHead(PyInterpreterState *interp) {
return interp->tstate_head;
return interp->threads.head;
}

PyThreadState *
Expand Down Expand Up @@ -1279,7 +1279,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;
Expand Down Expand Up @@ -1332,7 +1332,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;
Expand Down
2 changes: 1 addition & 1 deletion Python/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions Python/thread_nt.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "pycore_interp.h" // _PyInterpreterState.pythread_stacksize
#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize

/* This code implemented by [email protected] */
/* Fast NonRecursiveMutex support by Yakov Markovitch, [email protected] */
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}

Expand Down
8 changes: 4 additions & 4 deletions Python/thread_pthread.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "pycore_interp.h" // _PyInterpreterState.pythread_stacksize
#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize

/* Posix threads interface */

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}
}
Expand Down