From 5344cacebeece6bfa9f22902ee963aabadf4bb61 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 16 Dec 2021 14:38:03 -0700 Subject: [PATCH 1/6] Move PyThreadState.exc_state down to the bottom (and add comments). --- Include/cpython/pystate.h | 41 +++++++++++++++++++++++++++------------ Python/pystate.c | 8 ++++---- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index bcb1bb25a49409..170a842792cb21 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -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 */ @@ -181,6 +184,20 @@ struct _ts { 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; + + // XXX Move root_cframe down here. + // XXX Allocate the initial datastack_chunk here.. }; diff --git a/Python/pystate.c b/Python/pystate.c index e6175852c461c8..82b15fad2c9f68 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -785,7 +785,7 @@ 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 @@ -797,7 +797,7 @@ init_threadstate(PyThreadState *tstate, 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->datastack_chunk = NULL; @@ -1037,10 +1037,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"); } From 5d60c8b925726567299de67629006cd794d431c4 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 16 Dec 2021 14:40:49 -0700 Subject: [PATCH 2/6] Move PyThreadState.root_cframe down to the bottom. --- Include/cpython/pystate.h | 5 +++-- Python/pystate.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 170a842792cb21..cf437a8bfc984e 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -177,7 +177,6 @@ struct _ts { /* Unique thread state id. */ uint64_t id; - CFrame root_cframe; PyTraceInfo trace_info; _PyStackChunk *datastack_chunk; @@ -196,7 +195,9 @@ struct _ts { /* The thread's exception stack entry. (Always the last entry.) */ _PyErr_StackItem _exc_state; - // XXX Move root_cframe down here. + /* The bottom-most frame on the stack. */ + CFrame _root_cframe; + // XXX Allocate the initial datastack_chunk here.. }; diff --git a/Python/pystate.c b/Python/pystate.c index 82b15fad2c9f68..7f5fc1c67d0bf1 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -799,7 +799,7 @@ init_threadstate(PyThreadState *tstate, 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; From 13fabb73b816f13db46df328824f06ca3d70e694 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 28 Dec 2021 14:09:03 -0700 Subject: [PATCH 3/6] Move Py_DEFAULT_RECURSION_LIMIT to a header file. --- Include/internal/pycore_ceval.h | 5 +++++ Python/ceval.c | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 20508d4a687475..53d0b5c4549bc1 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -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); diff --git a/Python/ceval.c b/Python/ceval.c index d33cd4e1edb5dd..eed902fc687918 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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) { From 8d61bf31170737872a237042f247eebfe9a40cad Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 16 Dec 2021 15:12:45 -0700 Subject: [PATCH 4/6] Statically initialize PyThreadState.recursion_limit. --- Include/internal/pycore_runtime_init.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index e35c696610b94f..2b78090278c999 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -30,6 +30,7 @@ extern "C" { #define _PyThreadState_INIT \ { \ ._static = 1, \ + .recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \ } From 9f18b79f677f241b5e67c394d321f3439a61904e Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 16 Dec 2021 15:14:06 -0700 Subject: [PATCH 5/6] Statically initialize PyThreadState.context_ver. --- Include/internal/pycore_runtime_init.h | 1 + Python/pystate.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 2b78090278c999..78602d11bc838c 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -31,6 +31,7 @@ extern "C" { { \ ._static = 1, \ .recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \ + .context_ver = 1, \ } diff --git a/Python/pystate.c b/Python/pystate.c index 7f5fc1c67d0bf1..12cd18039d30ba 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -792,8 +792,6 @@ init_threadstate(PyThreadState *tstate, 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, From 3ef6a9c34705dfabe639f2979fe468a055cc2547 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 13 Jan 2022 14:31:02 -0700 Subject: [PATCH 6/6] Do not worry about pre-allocating the base datastack chunk. --- Include/cpython/pystate.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index cf437a8bfc984e..a35e5b803bd08d 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -197,8 +197,6 @@ struct _ts { /* The bottom-most frame on the stack. */ CFrame _root_cframe; - - // XXX Allocate the initial datastack_chunk here.. };