From 2aad06aa8f60e8487de4832309597617f83dcad1 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 10:30:04 -0600 Subject: [PATCH 01/20] Add a comment. --- Include/internal/pycore_gil.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Include/internal/pycore_gil.h b/Include/internal/pycore_gil.h index 8ebad37b686cd4..ff405e13270e01 100644 --- a/Include/internal/pycore_gil.h +++ b/Include/internal/pycore_gil.h @@ -20,6 +20,7 @@ extern "C" { #undef FORCE_SWITCHING #define FORCE_SWITCHING +/* ** The GIL ** */ struct _gil_runtime_state { /* microseconds (the Python API uses seconds, though) */ unsigned long interval; From e55fbdd15b651f3fbef05c630220f624d30edcd8 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 10:42:43 -0600 Subject: [PATCH 02/20] _gil_runtime_state -> _gil_state. --- Include/internal/pycore_gil.h | 2 +- Include/internal/pycore_interp.h | 1 + Include/internal/pycore_runtime.h | 4 ++-- Python/ceval_gil.c | 24 ++++++++++++------------ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Include/internal/pycore_gil.h b/Include/internal/pycore_gil.h index ff405e13270e01..56bcc1ca2c61ef 100644 --- a/Include/internal/pycore_gil.h +++ b/Include/internal/pycore_gil.h @@ -21,7 +21,7 @@ extern "C" { #define FORCE_SWITCHING /* ** The GIL ** */ -struct _gil_runtime_state { +struct _gil_state { /* microseconds (the Python API uses seconds, though) */ unsigned long interval; /* Last PyThreadState holding / having held the GIL. This helps us diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index e7f914ec2fe521..fea6c8fbffe14b 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -18,6 +18,7 @@ extern "C" { #include "pycore_exceptions.h" // struct _Py_exc_state #include "pycore_floatobject.h" // struct _Py_float_state #include "pycore_genobject.h" // struct _Py_async_gen_state +#include "pycore_gil.h" // struct _gil_state #include "pycore_gc.h" // struct _gc_runtime_state #include "pycore_list.h" // struct _Py_list_state #include "pycore_tuple.h" // struct _Py_tuple_state diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 2c04ead45869fc..e77c78ec28c9e2 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -9,7 +9,7 @@ extern "C" { #endif #include "pycore_atomic.h" /* _Py_atomic_address */ -#include "pycore_gil.h" // struct _gil_runtime_state +#include "pycore_gil.h" // struct _gil_state #include "pycore_global_objects.h" // struct _Py_global_objects #include "pycore_interp.h" // PyInterpreterState #include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids @@ -26,7 +26,7 @@ struct _ceval_runtime_state { the main thread of the main interpreter can handle signals: see _Py_ThreadCanHandleSignals(). */ _Py_atomic_int signals_pending; - struct _gil_runtime_state gil; + struct _gil_state gil; }; /* GIL state */ diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index a6790866766795..5c4f1cb5811061 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -218,19 +218,19 @@ is_tstate_valid(PyThreadState *tstate) #define DEFAULT_INTERVAL 5000 -static void _gil_initialize(struct _gil_runtime_state *gil) +static void _gil_initialize(struct _gil_state *gil) { _Py_atomic_int uninitialized = {-1}; gil->locked = uninitialized; gil->interval = DEFAULT_INTERVAL; } -static int gil_created(struct _gil_runtime_state *gil) +static int gil_created(struct _gil_state *gil) { return (_Py_atomic_load_explicit(&gil->locked, _Py_memory_order_acquire) >= 0); } -static void create_gil(struct _gil_runtime_state *gil) +static void create_gil(struct _gil_state *gil) { MUTEX_INIT(gil->mutex); #ifdef FORCE_SWITCHING @@ -245,7 +245,7 @@ static void create_gil(struct _gil_runtime_state *gil) _Py_atomic_store_explicit(&gil->locked, 0, _Py_memory_order_release); } -static void destroy_gil(struct _gil_runtime_state *gil) +static void destroy_gil(struct _gil_state *gil) { /* some pthread-like implementations tie the mutex to the cond * and must have the cond destroyed first. @@ -262,7 +262,7 @@ static void destroy_gil(struct _gil_runtime_state *gil) } #ifdef HAVE_FORK -static void recreate_gil(struct _gil_runtime_state *gil) +static void recreate_gil(struct _gil_state *gil) { _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked); /* XXX should we destroy the old OS resources here? */ @@ -274,7 +274,7 @@ static void drop_gil(struct _ceval_runtime_state *ceval, struct _ceval_state *ceval2, PyThreadState *tstate) { - struct _gil_runtime_state *gil = &ceval->gil; + struct _gil_state *gil = &ceval->gil; if (!_Py_atomic_load_relaxed(&gil->locked)) { Py_FatalError("drop_gil: GIL is not locked"); } @@ -358,7 +358,7 @@ take_gil(PyThreadState *tstate) PyInterpreterState *interp = tstate->interp; struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; - struct _gil_runtime_state *gil = &ceval->gil; + struct _gil_state *gil = &ceval->gil; /* Check that _PyEval_InitThreads() was called to create the lock */ assert(gil_created(gil)); @@ -450,13 +450,13 @@ take_gil(PyThreadState *tstate) void _PyEval_SetSwitchInterval(unsigned long microseconds) { - struct _gil_runtime_state *gil = &_PyRuntime.ceval.gil; + struct _gil_state *gil = &_PyRuntime.ceval.gil; gil->interval = microseconds; } unsigned long _PyEval_GetSwitchInterval() { - struct _gil_runtime_state *gil = &_PyRuntime.ceval.gil; + struct _gil_state *gil = &_PyRuntime.ceval.gil; return gil->interval; } @@ -484,7 +484,7 @@ _PyEval_InitGIL(PyThreadState *tstate) return _PyStatus_OK(); } - struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil; + struct _gil_state *gil = &tstate->interp->runtime->ceval.gil; assert(!gil_created(gil)); PyThread_init_thread(); @@ -506,7 +506,7 @@ _PyEval_FiniGIL(PyInterpreterState *interp) return; } - struct _gil_runtime_state *gil = &interp->runtime->ceval.gil; + struct _gil_state *gil = &interp->runtime->ceval.gil; if (!gil_created(gil)) { /* First Py_InitializeFromConfig() call: the GIL doesn't exist yet: do nothing. */ @@ -598,7 +598,7 @@ _PyEval_ReInitThreads(PyThreadState *tstate) { _PyRuntimeState *runtime = tstate->interp->runtime; - struct _gil_runtime_state *gil = &runtime->ceval.gil; + struct _gil_state *gil = &runtime->ceval.gil; if (!gil_created(gil)) { return _PyStatus_OK(); } From 711b19d43b7dfaa8facad06a8b50276f3232204d Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 11:50:57 -0600 Subject: [PATCH 03/20] Pass PyInterpreterState to _PyEval_ThreadInitialized(). --- Include/internal/pycore_ceval.h | 2 +- Python/ceval_gil.c | 14 ++++++++++---- Python/pystate.c | 7 ++++--- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 4914948c6ca744..bc8cdfb6a5a21a 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -103,7 +103,7 @@ _PyEval_Vector(PyThreadState *tstate, PyObject* const* args, size_t argcount, PyObject *kwnames); -extern int _PyEval_ThreadsInitialized(struct pyruntimestate *runtime); +extern int _PyEval_ThreadsInitialized(PyInterpreterState *interp); extern PyStatus _PyEval_InitGIL(PyThreadState *tstate); extern void _PyEval_FiniGIL(PyInterpreterState *interp); diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 5c4f1cb5811061..a3d1740dd9d262 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -462,16 +462,22 @@ unsigned long _PyEval_GetSwitchInterval() int -_PyEval_ThreadsInitialized(_PyRuntimeState *runtime) +_PyEval_ThreadsInitialized(PyInterpreterState *interp) { - return gil_created(&runtime->ceval.gil); + if (interp == NULL) { + interp = &_PyRuntime.main; + if (interp == NULL) { + return 0; + } + } + return gil_created(&interp->runtime->ceval.gil); } int PyEval_ThreadsInitialized(void) { - _PyRuntimeState *runtime = &_PyRuntime; - return _PyEval_ThreadsInitialized(runtime); + PyInterpreterState *interp = _PyInterpreterState_GET(); + return _PyEval_ThreadsInitialized(interp); } PyStatus diff --git a/Python/pystate.c b/Python/pystate.c index a0d61d7ebb3be9..75a4aa2e9420eb 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1677,9 +1677,10 @@ PyGILState_Ensure(void) spells out other issues. Embedders are expected to have called Py_Initialize(). */ - /* Ensure that _PyEval_InitThreads() and _PyGILState_Init() have been - called by Py_Initialize() */ - assert(_PyEval_ThreadsInitialized(runtime)); + /* Ensure that _PyEval_InitThreads() has been called by Py_Initialize() */ + // XXX Use the appropriate interpreter. + assert(runtime->main && _PyEval_ThreadsInitialized(runtime->main)); + /* Ensure that _PyGILState_Init() has been called by Py_Initialize() */ assert(gilstate->autoInterpreterState); PyThreadState *tcur = (PyThreadState *)PyThread_tss_get(&gilstate->autoTSSkey); From dba446005c301df7c5482f53de79a298c09acb71 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 12:38:22 -0600 Subject: [PATCH 04/20] runtime->main -> runtime->interpreters.main. --- Python/ceval_gil.c | 2 +- Python/pystate.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index a3d1740dd9d262..c0e16330c62c74 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -465,7 +465,7 @@ int _PyEval_ThreadsInitialized(PyInterpreterState *interp) { if (interp == NULL) { - interp = &_PyRuntime.main; + interp = _PyRuntime.interpreters.main; if (interp == NULL) { return 0; } diff --git a/Python/pystate.c b/Python/pystate.c index 75a4aa2e9420eb..196b0bdfb70534 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1679,7 +1679,8 @@ PyGILState_Ensure(void) /* Ensure that _PyEval_InitThreads() has been called by Py_Initialize() */ // XXX Use the appropriate interpreter. - assert(runtime->main && _PyEval_ThreadsInitialized(runtime->main)); + assert(runtime->interpreters.main && + _PyEval_ThreadsInitialized(runtime->interpreters.main)); /* Ensure that _PyGILState_Init() has been called by Py_Initialize() */ assert(gilstate->autoInterpreterState); From 5342672d57a40cd4b24b4b96fd8112cbf5cde9aa Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 12:39:01 -0600 Subject: [PATCH 05/20] Pass PyInterpreterState to _PyEval_InitState(). --- Include/internal/pycore_ceval.h | 2 +- Python/ceval_gil.c | 5 +++-- Python/pystate.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index bc8cdfb6a5a21a..5dabb9d35040db 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -29,7 +29,7 @@ struct _ceval_runtime_state; extern void _Py_FinishPendingCalls(PyThreadState *tstate); extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *); -extern void _PyEval_InitState(struct _ceval_state *, PyThread_type_lock); +extern void _PyEval_InitState(PyInterpreterState *, PyThread_type_lock); extern void _PyEval_FiniState(struct _ceval_state *ceval); PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp); PyAPI_FUNC(int) _PyEval_AddPendingCall( diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index c0e16330c62c74..6877988244dae7 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -908,11 +908,12 @@ _PyEval_InitRuntimeState(struct _ceval_runtime_state *ceval) } void -_PyEval_InitState(struct _ceval_state *ceval, PyThread_type_lock pending_lock) +_PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock) { + struct _ceval_state *ceval = &interp->ceval; + struct _pending_calls *pending = &ceval->pending; assert(pending->lock == NULL); - pending->lock = pending_lock; } diff --git a/Python/pystate.c b/Python/pystate.c index 196b0bdfb70534..fa2a8f9541d2ad 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -305,7 +305,7 @@ init_interpreter(PyInterpreterState *interp, assert(next != NULL || (interp == runtime->interpreters.main)); interp->next = next; - _PyEval_InitState(&interp->ceval, pending_lock); + _PyEval_InitState(interp, pending_lock); _PyGC_InitState(&interp->gc); PyConfig_InitPythonConfig(&interp->config); _PyType_InitCache(interp); From f2361d7b88464d6557967214175615503269af9f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 14:01:47 -0600 Subject: [PATCH 06/20] Label some struct fields. --- Include/internal/pycore_interp.h | 1 + Include/internal/pycore_runtime.h | 1 + 2 files changed, 2 insertions(+) diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index fea6c8fbffe14b..d8da63f427f458 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -50,6 +50,7 @@ struct _ceval_state { _Py_atomic_int eval_breaker; /* Request for dropping the GIL */ _Py_atomic_int gil_drop_request; + /* Pending calls */ struct _pending_calls pending; }; diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index e77c78ec28c9e2..cf2b240c72e86b 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -26,6 +26,7 @@ struct _ceval_runtime_state { the main thread of the main interpreter can handle signals: see _Py_ThreadCanHandleSignals(). */ _Py_atomic_int signals_pending; + /* The GIL */ struct _gil_state gil; }; From adc09a05106baa925626463afd6a652776b10ca7 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 15:19:47 -0600 Subject: [PATCH 07/20] Add _get_gil(). --- Python/ceval_gil.c | 161 ++++++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 76 deletions(-) diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 6877988244dae7..52c2987aa77046 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -60,70 +60,70 @@ the GIL eventually anyway. */ static inline void COMPUTE_EVAL_BREAKER(PyInterpreterState *interp, - struct _ceval_runtime_state *ceval, - struct _ceval_state *ceval2) + struct _ceval_runtime_state *shared_ceval, + struct _ceval_state *ceval) { - _Py_atomic_store_relaxed(&ceval2->eval_breaker, - _Py_atomic_load_relaxed_int32(&ceval2->gil_drop_request) - | (_Py_atomic_load_relaxed_int32(&ceval->signals_pending) + _Py_atomic_store_relaxed(&ceval->eval_breaker, + _Py_atomic_load_relaxed_int32(&ceval->gil_drop_request) + | (_Py_atomic_load_relaxed_int32(&shared_ceval->signals_pending) && _Py_ThreadCanHandleSignals(interp)) - | (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do) + | (_Py_atomic_load_relaxed_int32(&ceval->pending.calls_to_do) && _Py_ThreadCanHandlePendingCalls()) - | ceval2->pending.async_exc); + | ceval->pending.async_exc); } static inline void SET_GIL_DROP_REQUEST(PyInterpreterState *interp) { - struct _ceval_state *ceval2 = &interp->ceval; - _Py_atomic_store_relaxed(&ceval2->gil_drop_request, 1); - _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1); + struct _ceval_state *ceval = &interp->ceval; + _Py_atomic_store_relaxed(&ceval->gil_drop_request, 1); + _Py_atomic_store_relaxed(&ceval->eval_breaker, 1); } static inline void RESET_GIL_DROP_REQUEST(PyInterpreterState *interp) { - struct _ceval_runtime_state *ceval = &interp->runtime->ceval; - struct _ceval_state *ceval2 = &interp->ceval; - _Py_atomic_store_relaxed(&ceval2->gil_drop_request, 0); - COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + struct _ceval_runtime_state *shared_ceval = &interp->runtime->ceval; + struct _ceval_state *ceval = &interp->ceval; + _Py_atomic_store_relaxed(&ceval->gil_drop_request, 0); + COMPUTE_EVAL_BREAKER(interp, shared_ceval, ceval); } static inline void SIGNAL_PENDING_CALLS(PyInterpreterState *interp) { - struct _ceval_runtime_state *ceval = &interp->runtime->ceval; - struct _ceval_state *ceval2 = &interp->ceval; - _Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 1); - COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + struct _ceval_runtime_state *shared_ceval = &interp->runtime->ceval; + struct _ceval_state *ceval = &interp->ceval; + _Py_atomic_store_relaxed(&ceval->pending.calls_to_do, 1); + COMPUTE_EVAL_BREAKER(interp, shared_ceval, ceval); } static inline void UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp) { - struct _ceval_runtime_state *ceval = &interp->runtime->ceval; - struct _ceval_state *ceval2 = &interp->ceval; - _Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 0); - COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + struct _ceval_runtime_state *shared_ceval = &interp->runtime->ceval; + struct _ceval_state *ceval = &interp->ceval; + _Py_atomic_store_relaxed(&ceval->pending.calls_to_do, 0); + COMPUTE_EVAL_BREAKER(interp, shared_ceval, ceval); } static inline void SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp, int force) { - struct _ceval_runtime_state *ceval = &interp->runtime->ceval; - struct _ceval_state *ceval2 = &interp->ceval; - _Py_atomic_store_relaxed(&ceval->signals_pending, 1); + struct _ceval_runtime_state *shared_ceval = &interp->runtime->ceval; + struct _ceval_state *ceval = &interp->ceval; + _Py_atomic_store_relaxed(&shared_ceval->signals_pending, 1); if (force) { - _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1); + _Py_atomic_store_relaxed(&ceval->eval_breaker, 1); } else { /* eval_breaker is not set to 1 if thread_can_handle_signals() is false */ - COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + COMPUTE_EVAL_BREAKER(interp, shared_ceval, ceval); } } @@ -131,29 +131,29 @@ SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp, int force) static inline void UNSIGNAL_PENDING_SIGNALS(PyInterpreterState *interp) { - struct _ceval_runtime_state *ceval = &interp->runtime->ceval; - struct _ceval_state *ceval2 = &interp->ceval; - _Py_atomic_store_relaxed(&ceval->signals_pending, 0); - COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + struct _ceval_runtime_state *shared_ceval = &interp->runtime->ceval; + struct _ceval_state *ceval = &interp->ceval; + _Py_atomic_store_relaxed(&shared_ceval->signals_pending, 0); + COMPUTE_EVAL_BREAKER(interp, shared_ceval, ceval); } static inline void SIGNAL_ASYNC_EXC(PyInterpreterState *interp) { - struct _ceval_state *ceval2 = &interp->ceval; - ceval2->pending.async_exc = 1; - _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1); + struct _ceval_state *ceval = &interp->ceval; + ceval->pending.async_exc = 1; + _Py_atomic_store_relaxed(&ceval->eval_breaker, 1); } static inline void UNSIGNAL_ASYNC_EXC(PyInterpreterState *interp) { - struct _ceval_runtime_state *ceval = &interp->runtime->ceval; - struct _ceval_state *ceval2 = &interp->ceval; - ceval2->pending.async_exc = 0; - COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + struct _ceval_runtime_state *shared_ceval = &interp->runtime->ceval; + struct _ceval_state *ceval = &interp->ceval; + ceval->pending.async_exc = 0; + COMPUTE_EVAL_BREAKER(interp, shared_ceval, ceval); } #ifndef NDEBUG @@ -216,6 +216,14 @@ is_tstate_valid(PyThreadState *tstate) } \ +static inline struct _gil_state * +_get_gil(PyInterpreterState *interp) +{ + assert(interp->runtime == &_PyRuntime); + return &_PyRuntime.ceval.gil; +} + + #define DEFAULT_INTERVAL 5000 static void _gil_initialize(struct _gil_state *gil) @@ -271,10 +279,9 @@ static void recreate_gil(struct _gil_state *gil) #endif static void -drop_gil(struct _ceval_runtime_state *ceval, struct _ceval_state *ceval2, +drop_gil(struct _gil_state *gil, struct _ceval_state *ceval, PyThreadState *tstate) { - struct _gil_state *gil = &ceval->gil; if (!_Py_atomic_load_relaxed(&gil->locked)) { Py_FatalError("drop_gil: GIL is not locked"); } @@ -294,7 +301,7 @@ drop_gil(struct _ceval_runtime_state *ceval, struct _ceval_state *ceval2, MUTEX_UNLOCK(gil->mutex); #ifdef FORCE_SWITCHING - if (_Py_atomic_load_relaxed(&ceval2->gil_drop_request) && tstate != NULL) { + if (_Py_atomic_load_relaxed(&ceval->gil_drop_request) && tstate != NULL) { MUTEX_LOCK(gil->switch_mutex); /* Not switched yet => wait */ if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) == tstate) @@ -356,9 +363,9 @@ take_gil(PyThreadState *tstate) assert(is_tstate_valid(tstate)); PyInterpreterState *interp = tstate->interp; - struct _ceval_runtime_state *ceval = &interp->runtime->ceval; - struct _ceval_state *ceval2 = &interp->ceval; - struct _gil_state *gil = &ceval->gil; + struct _ceval_runtime_state *shared_ceval = &interp->runtime->ceval; + struct _ceval_state *ceval = &interp->ceval; + struct _gil_state *gil = _get_gil(interp); /* Check that _PyEval_InitThreads() was called to create the lock */ assert(gil_created(gil)); @@ -421,12 +428,12 @@ take_gil(PyThreadState *tstate) in take_gil() while the main thread called wait_for_thread_shutdown() from Py_Finalize(). */ MUTEX_UNLOCK(gil->mutex); - drop_gil(ceval, ceval2, tstate); + drop_gil(gil, ceval, tstate); PyThread_exit_thread(); } assert(is_tstate_valid(tstate)); - if (_Py_atomic_load_relaxed(&ceval2->gil_drop_request)) { + if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) { RESET_GIL_DROP_REQUEST(interp); } else { @@ -435,7 +442,7 @@ take_gil(PyThreadState *tstate) handle signals. Note: RESET_GIL_DROP_REQUEST() calls COMPUTE_EVAL_BREAKER(). */ - COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + COMPUTE_EVAL_BREAKER(interp, shared_ceval, ceval); } /* Don't access tstate if the thread must exit */ @@ -450,13 +457,15 @@ take_gil(PyThreadState *tstate) void _PyEval_SetSwitchInterval(unsigned long microseconds) { - struct _gil_state *gil = &_PyRuntime.ceval.gil; + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct _gil_state *gil = _get_gil(interp); gil->interval = microseconds; } unsigned long _PyEval_GetSwitchInterval() { - struct _gil_state *gil = &_PyRuntime.ceval.gil; + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct _gil_state *gil = _get_gil(interp); return gil->interval; } @@ -470,7 +479,8 @@ _PyEval_ThreadsInitialized(PyInterpreterState *interp) return 0; } } - return gil_created(&interp->runtime->ceval.gil); + struct _gil_state *gil = _get_gil(interp); + return gil_created(gil); } int @@ -490,7 +500,7 @@ _PyEval_InitGIL(PyThreadState *tstate) return _PyStatus_OK(); } - struct _gil_state *gil = &tstate->interp->runtime->ceval.gil; + struct _gil_state *gil = _get_gil(tstate->interp); assert(!gil_created(gil)); PyThread_init_thread(); @@ -512,7 +522,7 @@ _PyEval_FiniGIL(PyInterpreterState *interp) return; } - struct _gil_state *gil = &interp->runtime->ceval.gil; + struct _gil_state *gil = _get_gil(interp); if (!gil_created(gil)) { /* First Py_InitializeFromConfig() call: the GIL doesn't exist yet: do nothing. */ @@ -554,17 +564,17 @@ PyEval_ReleaseLock(void) /* This function must succeed when the current thread state is NULL. We therefore avoid PyThreadState_Get() which dumps a fatal error in debug mode. */ - struct _ceval_runtime_state *ceval = &runtime->ceval; - struct _ceval_state *ceval2 = &tstate->interp->ceval; - drop_gil(ceval, ceval2, tstate); + struct _gil_state *gil = _get_gil(tstate->interp); + struct _ceval_state *ceval = &tstate->interp->ceval; + drop_gil(gil, ceval, tstate); } void _PyEval_ReleaseLock(PyThreadState *tstate) { - struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval; - struct _ceval_state *ceval2 = &tstate->interp->ceval; - drop_gil(ceval, ceval2, tstate); + struct _gil_state *gil = _get_gil(tstate->interp); + struct _ceval_state *ceval = &tstate->interp->ceval; + drop_gil(gil, ceval, tstate); } void @@ -590,9 +600,9 @@ PyEval_ReleaseThread(PyThreadState *tstate) if (new_tstate != tstate) { Py_FatalError("wrong thread state"); } - struct _ceval_runtime_state *ceval = &runtime->ceval; - struct _ceval_state *ceval2 = &tstate->interp->ceval; - drop_gil(ceval, ceval2, tstate); + struct _gil_state *gil = _get_gil(tstate->interp); + struct _ceval_state *ceval = &tstate->interp->ceval; + drop_gil(gil, ceval, tstate); } #ifdef HAVE_FORK @@ -604,7 +614,7 @@ _PyEval_ReInitThreads(PyThreadState *tstate) { _PyRuntimeState *runtime = tstate->interp->runtime; - struct _gil_state *gil = &runtime->ceval.gil; + struct _gil_state *gil = _get_gil(tstate->interp); if (!gil_created(gil)) { return _PyStatus_OK(); } @@ -639,10 +649,10 @@ PyEval_SaveThread(void) PyThreadState *tstate = _PyThreadState_Swap(&runtime->gilstate, NULL); _Py_EnsureTstateNotNULL(tstate); - struct _ceval_runtime_state *ceval = &runtime->ceval; - struct _ceval_state *ceval2 = &tstate->interp->ceval; - assert(gil_created(&ceval->gil)); - drop_gil(ceval, ceval2, tstate); + struct _gil_state *gil = _get_gil(tstate->interp); + struct _ceval_state *ceval = &tstate->interp->ceval; + assert(gil_created(gil)); + drop_gil(gil, ceval, tstate); return tstate; } @@ -910,9 +920,7 @@ _PyEval_InitRuntimeState(struct _ceval_runtime_state *ceval) void _PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock) { - struct _ceval_state *ceval = &interp->ceval; - - struct _pending_calls *pending = &ceval->pending; + struct _pending_calls *pending = &interp->ceval.pending; assert(pending->lock == NULL); pending->lock = pending_lock; } @@ -933,30 +941,31 @@ int _Py_HandlePending(PyThreadState *tstate) { _PyRuntimeState * const runtime = &_PyRuntime; - struct _ceval_runtime_state *ceval = &runtime->ceval; + struct _ceval_runtime_state *shared_ceval = &runtime->ceval; /* Pending signals */ - if (_Py_atomic_load_relaxed_int32(&ceval->signals_pending)) { + if (_Py_atomic_load_relaxed_int32(&shared_ceval->signals_pending)) { if (handle_signals(tstate) != 0) { return -1; } } /* Pending calls */ - struct _ceval_state *ceval2 = &tstate->interp->ceval; - if (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do)) { + struct _ceval_state *ceval = &tstate->interp->ceval; + if (_Py_atomic_load_relaxed_int32(&ceval->pending.calls_to_do)) { if (make_pending_calls(tstate->interp) != 0) { return -1; } } /* GIL drop request */ - if (_Py_atomic_load_relaxed_int32(&ceval2->gil_drop_request)) { + if (_Py_atomic_load_relaxed_int32(&ceval->gil_drop_request)) { /* Give another thread a chance */ if (_PyThreadState_Swap(&runtime->gilstate, NULL) != tstate) { Py_FatalError("tstate mix-up"); } - drop_gil(ceval, ceval2, tstate); + struct _gil_state *gil = _get_gil(tstate->interp); + drop_gil(gil, ceval, tstate); /* Other threads may run now */ @@ -985,7 +994,7 @@ _Py_HandlePending(PyThreadState *tstate) // value. It prevents to interrupt the eval loop at every instruction if // the current Python thread cannot handle signals (if // _Py_ThreadCanHandleSignals() is false). - COMPUTE_EVAL_BREAKER(tstate->interp, ceval, ceval2); + COMPUTE_EVAL_BREAKER(tstate->interp, shared_ceval, ceval); #endif return 0; From 7014bffdc9b2bcaaaaea3d92e7d6aef303c75899 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 15:27:07 -0600 Subject: [PATCH 08/20] Pass the runtime to _PyEval_InitRuntimeState(). --- Include/internal/pycore_ceval.h | 2 +- Python/ceval_gil.c | 4 ++-- Python/pystate.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 5dabb9d35040db..6d3c6b43021ad4 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -28,7 +28,7 @@ struct _ceval_runtime_state; extern void _Py_FinishPendingCalls(PyThreadState *tstate); -extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *); +extern void _PyEval_InitRuntimeState(_PyRuntimeState *); extern void _PyEval_InitState(PyInterpreterState *, PyThread_type_lock); extern void _PyEval_FiniState(struct _ceval_state *ceval); PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp); diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 52c2987aa77046..060280ee7fef5d 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -912,9 +912,9 @@ Py_MakePendingCalls(void) /* The interpreter's recursion limit */ void -_PyEval_InitRuntimeState(struct _ceval_runtime_state *ceval) +_PyEval_InitRuntimeState(_PyRuntimeState *runtime) { - _gil_initialize(&ceval->gil); + _gil_initialize(&runtime->ceval.gil); } void diff --git a/Python/pystate.c b/Python/pystate.c index fa2a8f9541d2ad..a7df590f1dcd11 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -121,7 +121,7 @@ init_runtime(_PyRuntimeState *runtime, runtime->open_code_userdata = open_code_userdata; runtime->audit_hook_head = audit_hook_head; - _PyEval_InitRuntimeState(&runtime->ceval); + _PyEval_InitRuntimeState(runtime); PyPreConfig_InitPythonConfig(&runtime->preconfig); From 20260345eeadc2a45af54f6c9a65096ac277950b Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 15:53:34 -0600 Subject: [PATCH 09/20] Add some comments. --- Python/ceval_gil.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 060280ee7fef5d..a8989be330ed7f 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -920,6 +920,8 @@ _PyEval_InitRuntimeState(_PyRuntimeState *runtime) void _PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock) { + /* Everthing GIL-related is initialized in _PyEval_InitGIL(). */ + struct _pending_calls *pending = &interp->ceval.pending; assert(pending->lock == NULL); pending->lock = pending_lock; @@ -933,6 +935,8 @@ _PyEval_FiniState(struct _ceval_state *ceval) PyThread_free_lock(pending->lock); pending->lock = NULL; } + + /* Everthing GIL-related is finalized in _PyEval_FiniGIL(). */ } /* Handle signals, pending calls, GIL drop request From 3ce9695374dd2dce25ab66121c4460016cd3db3e Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 15:54:50 -0600 Subject: [PATCH 10/20] Add _GET_OWN_GIL(). --- Python/ceval_gil.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index a8989be330ed7f..ed1de938b7497b 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -216,6 +216,12 @@ is_tstate_valid(PyThreadState *tstate) } \ +/* Currently, the GIL is shared by all interpreters, + and only the main interpreter is responsible to create + and destroy it. */ +#define _GET_OWN_GIL(interp) \ + (_Py_IsMainInterpreter(interp) ? (&_PyRuntime.ceval.gil) : NULL) + static inline struct _gil_state * _get_gil(PyInterpreterState *interp) { @@ -493,14 +499,12 @@ PyEval_ThreadsInitialized(void) PyStatus _PyEval_InitGIL(PyThreadState *tstate) { - if (!_Py_IsMainInterpreter(tstate->interp)) { - /* Currently, the GIL is shared by all interpreters, - and only the main interpreter is responsible to create - and destroy it. */ + struct _gil_state *gil = _get_gil(tstate->interp); + if (gil != _GET_OWN_GIL(tstate->interp)) { + /* It's a shared GIL. */ + assert(!_Py_IsMainInterpreter(tstate->interp)); return _PyStatus_OK(); } - - struct _gil_state *gil = _get_gil(tstate->interp); assert(!gil_created(gil)); PyThread_init_thread(); @@ -515,14 +519,12 @@ _PyEval_InitGIL(PyThreadState *tstate) void _PyEval_FiniGIL(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - /* Currently, the GIL is shared by all interpreters, - and only the main interpreter is responsible to create - and destroy it. */ + struct _gil_state *gil = _get_gil(interp); + if (gil != _GET_OWN_GIL(interp)) { + /* It's a shared GIL. */ + assert(!_Py_IsMainInterpreter(interp)); return; } - - struct _gil_state *gil = _get_gil(interp); if (!gil_created(gil)) { /* First Py_InitializeFromConfig() call: the GIL doesn't exist yet: do nothing. */ From 57ca2fa9c974739920d9c65b1878d1089d1f6e97 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 16:06:40 -0600 Subject: [PATCH 11/20] Pass PyInterpreterState to _PyEval_FiniState(). --- Include/internal/pycore_ceval.h | 2 +- Python/ceval_gil.c | 4 ++-- Python/pystate.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 6d3c6b43021ad4..596d2f8abb623c 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -30,7 +30,7 @@ struct _ceval_runtime_state; extern void _Py_FinishPendingCalls(PyThreadState *tstate); extern void _PyEval_InitRuntimeState(_PyRuntimeState *); extern void _PyEval_InitState(PyInterpreterState *, PyThread_type_lock); -extern void _PyEval_FiniState(struct _ceval_state *ceval); +extern void _PyEval_FiniState(PyInterpreterState *); PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp); PyAPI_FUNC(int) _PyEval_AddPendingCall( PyInterpreterState *interp, diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index ed1de938b7497b..1799d54c099e14 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -930,9 +930,9 @@ _PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock) } void -_PyEval_FiniState(struct _ceval_state *ceval) +_PyEval_FiniState(PyInterpreterState *interp) { - struct _pending_calls *pending = &ceval->pending; + struct _pending_calls *pending = &interp->ceval.pending; if (pending->lock != NULL) { PyThread_free_lock(pending->lock); pending->lock = NULL; diff --git a/Python/pystate.c b/Python/pystate.c index a7df590f1dcd11..23de70acc2c4a2 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -495,7 +495,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp) struct pyinterpreters *interpreters = &runtime->interpreters; zapthreads(interp, 0); - _PyEval_FiniState(&interp->ceval); + _PyEval_FiniState(interp); /* Delete current thread. After this, many C API calls become crashy. */ _PyThreadState_Swap(&runtime->gilstate, NULL); From 936c86dcdda4986456e347968448eba056378e67 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 16:14:57 -0600 Subject: [PATCH 12/20] Call _gil_initialize() in _PyEval_InitState(). --- Python/ceval_gil.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 1799d54c099e14..a97857095b4061 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -916,13 +916,19 @@ Py_MakePendingCalls(void) void _PyEval_InitRuntimeState(_PyRuntimeState *runtime) { - _gil_initialize(&runtime->ceval.gil); + //_gil_initialize(&runtime->ceval.gil); } void _PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock) { - /* Everthing GIL-related is initialized in _PyEval_InitGIL(). */ + /* Each interpreter is responsible to create and destroy + its own GIL. Interpreters that share a GIL skip this step. */ + struct _gil_state *gil = _get_gil(interp); + if (gil == _GET_OWN_GIL(interp)) { + _gil_initialize(gil); + /* Everthing else GIL-related is initialized in _PyEval_InitGIL(). */ + } struct _pending_calls *pending = &interp->ceval.pending; assert(pending->lock == NULL); From 66ca3e486baa228d4300a97438134b64401d6ae2 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 16:17:14 -0600 Subject: [PATCH 13/20] Drop _PyEval_InitRuntimeState(). --- Include/internal/pycore_ceval.h | 1 - Python/ceval_gil.c | 6 ------ Python/pystate.c | 2 -- 3 files changed, 9 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 596d2f8abb623c..ccd4e2e699c93a 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -28,7 +28,6 @@ struct _ceval_runtime_state; extern void _Py_FinishPendingCalls(PyThreadState *tstate); -extern void _PyEval_InitRuntimeState(_PyRuntimeState *); extern void _PyEval_InitState(PyInterpreterState *, PyThread_type_lock); extern void _PyEval_FiniState(PyInterpreterState *); PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp); diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index a97857095b4061..572b9c8ddcddb9 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -913,12 +913,6 @@ Py_MakePendingCalls(void) /* The interpreter's recursion limit */ -void -_PyEval_InitRuntimeState(_PyRuntimeState *runtime) -{ - //_gil_initialize(&runtime->ceval.gil); -} - void _PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock) { diff --git a/Python/pystate.c b/Python/pystate.c index 23de70acc2c4a2..a02eb20f03cb68 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -121,8 +121,6 @@ init_runtime(_PyRuntimeState *runtime, runtime->open_code_userdata = open_code_userdata; runtime->audit_hook_head = audit_hook_head; - _PyEval_InitRuntimeState(runtime); - PyPreConfig_InitPythonConfig(&runtime->preconfig); runtime->interpreters.mutex = interpreters_mutex; From 6d0932079c5da629542da8fd0ddbf8c37957e068 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 12:39:39 -0600 Subject: [PATCH 14/20] Move the GIL to PyInterpreterState (but still share). --- Include/internal/pycore_interp.h | 2 ++ Include/internal/pycore_runtime.h | 3 --- Python/ceval_gil.c | 9 +++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index d8da63f427f458..6b123b8d96d5a4 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -50,6 +50,8 @@ struct _ceval_state { _Py_atomic_int eval_breaker; /* Request for dropping the GIL */ _Py_atomic_int gil_drop_request; + /* The GIL */ + struct _gil_state gil; /* Pending calls */ struct _pending_calls pending; }; diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index cf2b240c72e86b..d205f7afd0a46b 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -9,7 +9,6 @@ extern "C" { #endif #include "pycore_atomic.h" /* _Py_atomic_address */ -#include "pycore_gil.h" // struct _gil_state #include "pycore_global_objects.h" // struct _Py_global_objects #include "pycore_interp.h" // PyInterpreterState #include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids @@ -26,8 +25,6 @@ struct _ceval_runtime_state { the main thread of the main interpreter can handle signals: see _Py_ThreadCanHandleSignals(). */ _Py_atomic_int signals_pending; - /* The GIL */ - struct _gil_state gil; }; /* GIL state */ diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 572b9c8ddcddb9..78bc42bddd97f4 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -220,13 +220,18 @@ is_tstate_valid(PyThreadState *tstate) and only the main interpreter is responsible to create and destroy it. */ #define _GET_OWN_GIL(interp) \ - (_Py_IsMainInterpreter(interp) ? (&_PyRuntime.ceval.gil) : NULL) + (_Py_IsMainInterpreter(interp) \ + ? (&_PyRuntime.interpreters.main->ceval.gil) \ + : NULL) static inline struct _gil_state * _get_gil(PyInterpreterState *interp) { + //if (interp->config->_isolated_interpreter) { + // return &interp->ceval.gil; + //} assert(interp->runtime == &_PyRuntime); - return &_PyRuntime.ceval.gil; + return &_PyRuntime.interpreters.main->ceval.gil; } From 507599297eb2857dd9cdd6d99cc9f339d9552586 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 12:53:55 -0600 Subject: [PATCH 15/20] Keep sharing the GIL. --- Python/ceval_gil.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 78bc42bddd97f4..32a3896fecd9bc 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -227,9 +227,6 @@ is_tstate_valid(PyThreadState *tstate) static inline struct _gil_state * _get_gil(PyInterpreterState *interp) { - //if (interp->config->_isolated_interpreter) { - // return &interp->ceval.gil; - //} assert(interp->runtime == &_PyRuntime); return &_PyRuntime.interpreters.main->ceval.gil; } From f39c883a6e7443d4717896a6a8cdaacb163d8600 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 13:28:57 -0600 Subject: [PATCH 16/20] Check for GIL ownership. --- Python/ceval_gil.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 32a3896fecd9bc..83d66db38d5545 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -220,9 +220,7 @@ is_tstate_valid(PyThreadState *tstate) and only the main interpreter is responsible to create and destroy it. */ #define _GET_OWN_GIL(interp) \ - (_Py_IsMainInterpreter(interp) \ - ? (&_PyRuntime.interpreters.main->ceval.gil) \ - : NULL) + (&interp->ceval.gil) static inline struct _gil_state * _get_gil(PyInterpreterState *interp) From ae2eb3cfaf9146d955ebdc5255d8d20b7b6f7dc7 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 12 Sep 2022 13:30:52 -0600 Subject: [PATCH 17/20] Stop sharing the GIL if configured as "isolated". --- Python/ceval_gil.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 83d66db38d5545..ab5b8f4cf50043 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -225,7 +225,9 @@ is_tstate_valid(PyThreadState *tstate) static inline struct _gil_state * _get_gil(PyInterpreterState *interp) { - assert(interp->runtime == &_PyRuntime); + if (interp->config._isolated_interpreter) { + return _GET_OWN_GIL(interp); + } return &_PyRuntime.interpreters.main->ceval.gil; } From b984a34e43b8d90fa07a2284bf71d1bbd5e354b0 Mon Sep 17 00:00:00 2001 From: Anthony Shaw Date: Wed, 3 May 2023 13:48:50 -0500 Subject: [PATCH 18/20] add bool as shareable --- Lib/test/test__xxsubinterpreters.py | 7 +++++-- Python/pystate.c | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py index f20aae8e21c66f..1676749b59d545 100644 --- a/Lib/test/test__xxsubinterpreters.py +++ b/Lib/test/test__xxsubinterpreters.py @@ -313,6 +313,8 @@ def test_default_shareables(self): 'spam', 10, -10, + True, + False, ] for obj in shareables: with self.subTest(obj): @@ -331,8 +333,6 @@ class SubBytes(bytes): not_shareables = [ # singletons - True, - False, NotImplemented, ..., # builtin types and objects @@ -400,6 +400,9 @@ def test_int(self): self._assert_values(itertools.chain(range(-1, 258), [sys.maxsize, -sys.maxsize - 1])) + def test_bool(self): + self._assert_values(True, False) + def test_non_shareable_int(self): ints = [ sys.maxsize + 1, diff --git a/Python/pystate.c b/Python/pystate.c index a02eb20f03cb68..42ca61dbd765a4 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2091,6 +2091,25 @@ _none_shared(PyObject *obj, _PyCrossInterpreterData *data) return 0; } +static PyObject * +_new_bool_object(_PyCrossInterpreterData *data) +{ + if ((unsigned char)data->data == 1){ + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +static int +_bool_shared(PyObject *obj, _PyCrossInterpreterData *data) +{ + data->data = (void *) (Py_IsTrue ? 1 : 0); + data->obj = NULL; + data->new_object = _new_bool_object; + data->free = NULL; // There is nothing to free. + return 0; +} + static void _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry) { @@ -2099,6 +2118,11 @@ _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry) Py_FatalError("could not register None for cross-interpreter sharing"); } + // Bool + if (_register_xidata(xidregistry, &PyBool_Type, _bool_shared) != 0) { + Py_FatalError("could not register bool for cross-interpreter sharing"); + } + // int if (_register_xidata(xidregistry, &PyLong_Type, _long_shared) != 0) { Py_FatalError("could not register int for cross-interpreter sharing"); From ea4c9eace972b66e73a8be6b3ff03fe518697a98 Mon Sep 17 00:00:00 2001 From: Anthony Shaw Date: Wed, 3 May 2023 14:09:06 -0500 Subject: [PATCH 19/20] add shareable floats --- Lib/test/test__xxsubinterpreters.py | 5 ++++- Python/pystate.c | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py index 1676749b59d545..ad46a9f2e2e549 100644 --- a/Lib/test/test__xxsubinterpreters.py +++ b/Lib/test/test__xxsubinterpreters.py @@ -315,6 +315,7 @@ def test_default_shareables(self): -10, True, False, + 100.0, ] for obj in shareables: with self.subTest(obj): @@ -340,7 +341,6 @@ class SubBytes(bytes): object, object(), Exception(), - 100.0, # user-defined types and objects Cheese, Cheese('Wensleydale'), @@ -400,6 +400,9 @@ def test_int(self): self._assert_values(itertools.chain(range(-1, 258), [sys.maxsize, -sys.maxsize - 1])) + def test_float(self): + self._assert_values([0.0, 1.1, -1.0, 0.12345678, -0.12345678]) + def test_bool(self): self._assert_values(True, False) diff --git a/Python/pystate.c b/Python/pystate.c index 42ca61dbd765a4..2847cf1130a06a 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2073,6 +2073,25 @@ _long_shared(PyObject *obj, _PyCrossInterpreterData *data) return 0; } +static PyObject * +_new_float_object(_PyCrossInterpreterData *data) +{ + double * value_ptr = data->data; + return PyFloat_FromDouble(*value_ptr); +} + +static int +_float_shared(PyObject *obj, _PyCrossInterpreterData *data) +{ + double *shared = PyMem_NEW(double, 1); + data->data = (void *)shared; + Py_INCREF(obj); + data->obj = obj; // Will be "released" (decref'ed) when data released. + data->new_object = _new_float_object; + data->free = PyMem_Free; + return 0; +} + static PyObject * _new_none_object(_PyCrossInterpreterData *data) { @@ -2128,6 +2147,11 @@ _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry) Py_FatalError("could not register int for cross-interpreter sharing"); } + // float + if (_register_xidata(xidregistry, &PyFloat_Type, _float_shared) != 0) { + Py_FatalError("could not register float for cross-interpreter sharing"); + } + // bytes if (_register_xidata(xidregistry, &PyBytes_Type, _bytes_shared) != 0) { Py_FatalError("could not register bytes for cross-interpreter sharing"); From f60d87c27e40b2effc234d37d7d597b4e961445b Mon Sep 17 00:00:00 2001 From: Anthony Shaw Date: Wed, 3 May 2023 14:28:09 -0500 Subject: [PATCH 20/20] use ll literal to avoid the upcast warning in MSVC --- Python/pystate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/pystate.c b/Python/pystate.c index 42ca61dbd765a4..e4538b196ac8ca 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2094,7 +2094,7 @@ _none_shared(PyObject *obj, _PyCrossInterpreterData *data) static PyObject * _new_bool_object(_PyCrossInterpreterData *data) { - if ((unsigned char)data->data == 1){ + if (data->data){ Py_RETURN_TRUE; } Py_RETURN_FALSE; @@ -2103,7 +2103,7 @@ _new_bool_object(_PyCrossInterpreterData *data) static int _bool_shared(PyObject *obj, _PyCrossInterpreterData *data) { - data->data = (void *) (Py_IsTrue ? 1 : 0); + data->data = (void *) (Py_IsTrue ? 1ll : 0ll); data->obj = NULL; data->new_object = _new_bool_object; data->free = NULL; // There is nothing to free.