Skip to content

Commit

Permalink
bpo-45953: Statically initialize all the PyThreadState fields we can. (
Browse files Browse the repository at this point in the history
  • Loading branch information
ericsnowcurrently authored Jan 14, 2022
1 parent d4e64cd commit 324908b
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 24 deletions.
42 changes: 29 additions & 13 deletions Include/cpython/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
};


Expand Down
5 changes: 5 additions & 0 deletions Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions Include/internal/pycore_runtime_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ extern "C" {
#define _PyThreadState_INIT \
{ \
._static = 1, \
.recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \
.context_ver = 1, \
}


Expand Down
4 changes: 0 additions & 4 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
12 changes: 5 additions & 7 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
}
Expand Down

0 comments on commit 324908b

Please sign in to comment.