summaryrefslogtreecommitdiffstats
path: root/Include
diff options
context:
space:
mode:
Diffstat (limited to 'Include')
-rw-r--r--Include/cpython/pystate.h5
-rw-r--r--Include/internal/pycore_ceval.h50
-rw-r--r--Include/internal/pycore_ceval_state.h11
-rw-r--r--Include/internal/pycore_gc.h2
-rw-r--r--Include/internal/pycore_runtime.h3
5 files changed, 39 insertions, 32 deletions
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index b99450a..ac7ff83 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -68,6 +68,11 @@ struct _ts {
PyThreadState *next;
PyInterpreterState *interp;
+ /* The global instrumentation version in high bits, plus flags indicating
+ when to break out of the interpreter loop in lower bits. See details in
+ pycore_ceval.h. */
+ uintptr_t eval_breaker;
+
struct {
/* Has been initialized to a safe state.
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index b158fc9..bf77526 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -42,7 +42,7 @@ PyAPI_FUNC(int) _PyEval_MakePendingCalls(PyThreadState *);
extern void _Py_FinishPendingCalls(PyThreadState *tstate);
extern void _PyEval_InitState(PyInterpreterState *);
-extern void _PyEval_SignalReceived(PyInterpreterState *interp);
+extern void _PyEval_SignalReceived(void);
// bitwise flags:
#define _Py_PENDING_MAINTHREADONLY 1
@@ -55,7 +55,6 @@ PyAPI_FUNC(int) _PyEval_AddPendingCall(
void *arg,
int flags);
-extern void _PyEval_SignalAsyncExc(PyInterpreterState *interp);
#ifdef HAVE_FORK
extern PyStatus _PyEval_ReInitThreads(PyThreadState *tstate);
#endif
@@ -200,40 +199,43 @@ int _PyEval_UnpackIterable(PyThreadState *tstate, PyObject *v, int argcnt, int a
void _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame);
-#define _PY_GIL_DROP_REQUEST_BIT 0
-#define _PY_SIGNALS_PENDING_BIT 1
-#define _PY_CALLS_TO_DO_BIT 2
-#define _PY_ASYNC_EXCEPTION_BIT 3
-#define _PY_GC_SCHEDULED_BIT 4
-#define _PY_EVAL_PLEASE_STOP_BIT 5
-#define _PY_EVAL_EXPLICIT_MERGE_BIT 6
+/* Bits that can be set in PyThreadState.eval_breaker */
+#define _PY_GIL_DROP_REQUEST_BIT (1U << 0)
+#define _PY_SIGNALS_PENDING_BIT (1U << 1)
+#define _PY_CALLS_TO_DO_BIT (1U << 2)
+#define _PY_ASYNC_EXCEPTION_BIT (1U << 3)
+#define _PY_GC_SCHEDULED_BIT (1U << 4)
+#define _PY_EVAL_PLEASE_STOP_BIT (1U << 5)
+#define _PY_EVAL_EXPLICIT_MERGE_BIT (1U << 6)
/* Reserve a few bits for future use */
#define _PY_EVAL_EVENTS_BITS 8
#define _PY_EVAL_EVENTS_MASK ((1 << _PY_EVAL_EVENTS_BITS)-1)
static inline void
-_Py_set_eval_breaker_bit(PyInterpreterState *interp, uint32_t bit, uint32_t set)
+_Py_set_eval_breaker_bit(PyThreadState *tstate, uintptr_t bit)
{
- assert(set == 0 || set == 1);
- uintptr_t to_set = set << bit;
- uintptr_t mask = ((uintptr_t)1) << bit;
- uintptr_t old = _Py_atomic_load_uintptr(&interp->ceval.eval_breaker);
- if ((old & mask) == to_set) {
- return;
- }
- uintptr_t new;
- do {
- new = (old & ~mask) | to_set;
- } while (!_Py_atomic_compare_exchange_uintptr(&interp->ceval.eval_breaker, &old, new));
+ _Py_atomic_or_uintptr(&tstate->eval_breaker, bit);
+}
+
+static inline void
+_Py_unset_eval_breaker_bit(PyThreadState *tstate, uintptr_t bit)
+{
+ _Py_atomic_and_uintptr(&tstate->eval_breaker, ~bit);
}
-static inline bool
-_Py_eval_breaker_bit_is_set(PyInterpreterState *interp, int32_t bit)
+static inline int
+_Py_eval_breaker_bit_is_set(PyThreadState *tstate, uintptr_t bit)
{
- return _Py_atomic_load_uintptr_relaxed(&interp->ceval.eval_breaker) & (((uintptr_t)1) << bit);
+ uintptr_t b = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker);
+ return (b & bit) != 0;
}
+// Free-threaded builds use these functions to set or unset a bit on all
+// threads in the given interpreter.
+void _Py_set_eval_breaker_bit_all(PyInterpreterState *interp, uintptr_t bit);
+void _Py_unset_eval_breaker_bit_all(PyInterpreterState *interp, uintptr_t bit);
+
#ifdef __cplusplus
}
diff --git a/Include/internal/pycore_ceval_state.h b/Include/internal/pycore_ceval_state.h
index 2873898..b453328 100644
--- a/Include/internal/pycore_ceval_state.h
+++ b/Include/internal/pycore_ceval_state.h
@@ -78,13 +78,10 @@ struct _ceval_runtime_state {
struct _ceval_state {
- /* This single variable consolidates all requests to break out of
- * the fast path in the eval loop.
- * It is by far the hottest field in this struct and
- * should be placed at the beginning. */
- uintptr_t eval_breaker;
- /* Avoid false sharing */
- int64_t padding[7];
+ /* This variable holds the global instrumentation version. When a thread is
+ running, this value is overlaid onto PyThreadState.eval_breaker so that
+ changes in the instrumentation version will trigger the eval breaker. */
+ uintptr_t instrumentation_version;
int recursion_limit;
struct _gil_runtime_state *gil;
int own_gil;
diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h
index a98864f..40414a8 100644
--- a/Include/internal/pycore_gc.h
+++ b/Include/internal/pycore_gc.h
@@ -286,7 +286,7 @@ extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs);
// Functions to clear types free lists
extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp);
-extern void _Py_ScheduleGC(PyInterpreterState *interp);
+extern void _Py_ScheduleGC(PyThreadState *tstate);
extern void _Py_RunGC(PyThreadState *tstate);
#ifdef __cplusplus
diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h
index 7c705d1..0c9c59e 100644
--- a/Include/internal/pycore_runtime.h
+++ b/Include/internal/pycore_runtime.h
@@ -191,7 +191,10 @@ typedef struct pyruntimestate {
int64_t next_id;
} interpreters;
+ /* Platform-specific identifier and PyThreadState, respectively, for the
+ main thread in the main interpreter. */
unsigned long main_thread;
+ PyThreadState *main_tstate;
/* ---------- IMPORTANT ---------------------------
The fields above this line are declared as early as