bpo-45953: Statically initialize all the PyThreadState fields we can. (gh-30590)

https://bugs.python.org/issue45953
This commit is contained in:
Eric Snow 2022-01-13 17:09:24 -07:00 committed by GitHub
parent d4e64cd4b0
commit 324908ba93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 41 additions and 24 deletions

View File

@ -53,12 +53,19 @@ typedef struct _cframe {
} CFrame;
typedef struct _err_stackitem {
/* This struct represents an entry on the exception stack, which is a
* per-coroutine state. (Coroutine in the computer science sense,
* including the thread and generators).
* This ensures that the exception state is not impacted by "yields"
* from an except handler.
/* This struct represents a single execution context where we might
* be currently handling an exception. It is a per-coroutine state
* (coroutine in the computer science sense, including the thread
* and generators).
*
* This is used as an entry on the exception stack, where each
* entry indicates if it is currently handling an exception.
* This ensures that the exception state is not impacted
* by "yields" from an except handler. The thread
* always has an entry (the bottom-most one).
*/
/* The exception currently being handled in this context, if any. */
PyObject *exc_value;
struct _err_stackitem *previous_item;
@ -112,13 +119,9 @@ struct _ts {
PyObject *curexc_value;
PyObject *curexc_traceback;
/* The exception currently being handled, if no coroutines/generators
* are present. Always last element on the stack referred to be exc_info.
*/
_PyErr_StackItem exc_state;
/* Pointer to the top of the stack of the exceptions currently
* being handled */
/* Pointer to the top of the exception stack for the exceptions
* we may be currently handling. (See _PyErr_StackItem above.)
* This is never NULL. */
_PyErr_StackItem *exc_info;
PyObject *dict; /* Stores per-thread state */
@ -174,13 +177,26 @@ struct _ts {
/* Unique thread state id. */
uint64_t id;
CFrame root_cframe;
PyTraceInfo trace_info;
_PyStackChunk *datastack_chunk;
PyObject **datastack_top;
PyObject **datastack_limit;
/* XXX signal handlers should also be here */
/* The following fields are here to avoid allocation during init.
The data is exposed through PyThreadState pointer fields.
These fields should not be accessed directly outside of init.
All other PyInterpreterState pointer fields are populated when
needed and default to NULL.
*/
/* The thread's exception stack entry. (Always the last entry.) */
_PyErr_StackItem _exc_state;
/* The bottom-most frame on the stack. */
CFrame _root_cframe;
};

View File

@ -12,9 +12,14 @@ extern "C" {
struct pyruntimestate;
struct _ceval_runtime_state;
#ifndef Py_DEFAULT_RECURSION_LIMIT
# define Py_DEFAULT_RECURSION_LIMIT 1000
#endif
#include "pycore_interp.h" // PyInterpreterState.eval_frame
#include "pycore_pystate.h" // _PyThreadState_GET()
extern void _Py_FinishPendingCalls(PyThreadState *tstate);
extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *);
extern void _PyEval_InitState(struct _ceval_state *, PyThread_type_lock);

View File

@ -41,6 +41,8 @@ extern "C" {
#define _PyThreadState_INIT \
{ \
._static = 1, \
.recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \
.context_ver = 1, \
}

View File

@ -737,10 +737,6 @@ Py_MakePendingCalls(void)
/* The interpreter's recursion limit */
#ifndef Py_DEFAULT_RECURSION_LIMIT
# define Py_DEFAULT_RECURSION_LIMIT 1000
#endif
void
_PyEval_InitRuntimeState(struct _ceval_runtime_state *ceval)
{

View File

@ -775,21 +775,19 @@ init_threadstate(PyThreadState *tstate,
next->prev = tstate;
}
tstate->next = next;
tstate->prev = NULL;
assert(tstate->prev == NULL);
tstate->thread_id = PyThread_get_thread_ident();
#ifdef PY_HAVE_THREAD_NATIVE_ID
tstate->native_thread_id = PyThread_get_thread_native_id();
#endif
tstate->context_ver = 1;
tstate->recursion_limit = interp->ceval.recursion_limit,
tstate->recursion_remaining = interp->ceval.recursion_limit,
tstate->exc_info = &tstate->exc_state;
tstate->exc_info = &tstate->_exc_state;
tstate->cframe = &tstate->root_cframe;
tstate->cframe = &tstate->_root_cframe;
tstate->datastack_chunk = NULL;
tstate->datastack_top = NULL;
tstate->datastack_limit = NULL;
@ -1027,10 +1025,10 @@ PyThreadState_Clear(PyThreadState *tstate)
Py_CLEAR(tstate->curexc_value);
Py_CLEAR(tstate->curexc_traceback);
Py_CLEAR(tstate->exc_state.exc_value);
Py_CLEAR(tstate->_exc_state.exc_value);
/* The stack of exception states should contain just this thread. */
if (verbose && tstate->exc_info != &tstate->exc_state) {
if (verbose && tstate->exc_info != &tstate->_exc_state) {
fprintf(stderr,
"PyThreadState_Clear: warning: thread still has a generator\n");
}