]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-45953: Statically initialize all the PyThreadState fields we can. (gh-30590)
authorEric Snow <ericsnowcurrently@gmail.com>
Fri, 14 Jan 2022 00:09:24 +0000 (17:09 -0700)
committerGitHub <noreply@github.com>
Fri, 14 Jan 2022 00:09:24 +0000 (17:09 -0700)
https://bugs.python.org/issue45953

Include/cpython/pystate.h
Include/internal/pycore_ceval.h
Include/internal/pycore_runtime_init.h
Python/ceval.c
Python/pystate.c

index bcb1bb25a4940955f90808dd71ebc358e1c7088c..a35e5b803bd08d7f011947fa565ef4fa01550b54 100644 (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;
 };
 
 
index 20508d4a687475c0ea1bbedcd919c261b5ea7986..53d0b5c4549bc198ebc11d01001c435493b8ae6d 100644 (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);
index fc768ff5d053f74d949a0f919b159763ceba8861..aa6612063d0ba914301307955b7d733ee7eacbf4 100644 (file)
@@ -41,6 +41,8 @@ extern "C" {
 #define _PyThreadState_INIT \
     { \
         ._static = 1, \
+        .recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \
+        .context_ver = 1, \
     }
 
 
index d33cd4e1edb5dde5a89e52b4715353dc1de1dc95..eed902fc687918ab67df6f3845ddd196e7fb07e7 100644 (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)
 {
index 50b36218960284f227a50e154cd15f78fd2ab66d..23156850bfeba0574665940bb3b321b0bf6e4935 100644 (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");
     }