Unverified Kaydet (Commit) 09532fee authored tarafından Victor Stinner's avatar Victor Stinner Kaydeden (comit) GitHub

bpo-36710: Add 'ceval' local variable to ceval.c (GH-12934)

Add "struct _ceval_runtime_state *ceval = &_PyRuntime.ceval;" local
variables to function to better highlight the dependency on the
global variable _PyRuntime and to point directly to _PyRuntime.ceval
field rather than on the larger _PyRuntime.

Changes:

* Add _PyRuntimeState_GetThreadState(runtime) macro.
* Add _PyEval_AddPendingCall(ceval, ...) and
  _PyThreadState_Swap(gilstate, ...) functions.
* _PyThreadState_GET() macro now calls
  _PyRuntimeState_GetThreadState() using &_PyRuntime.
* Add 'ceval' parameter to COMPUTE_EVAL_BREAKER(),
  SIGNAL_PENDING_SIGNALS(), _PyEval_SignalAsyncExc(),
  _PyEval_SignalReceived() and _PyEval_FiniThreads() macros and
  functions.
* Add 'tstate' parameter to call_function(), do_call_core() and
  do_raise().
* Add 'runtime' parameter to _Py_CURRENTLY_FINALIZING(),
  _Py_FinishPendingCalls() and _PyThreadState_DeleteExcept()
  macros and functions.
* Declare 'runtime', 'tstate', 'ceval' and 'eval_breaker' variables
  as constant.
üst f22cc69b
...@@ -58,7 +58,6 @@ PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf); ...@@ -58,7 +58,6 @@ PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf);
#endif #endif
PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg); PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg);
PyAPI_FUNC(void) _PyEval_SignalReceived(void);
PyAPI_FUNC(int) Py_MakePendingCalls(void); PyAPI_FUNC(int) Py_MakePendingCalls(void);
/* Protection against deeply nested recursive calls /* Protection against deeply nested recursive calls
...@@ -192,9 +191,6 @@ PyAPI_FUNC(void) PyEval_RestoreThread(PyThreadState *); ...@@ -192,9 +191,6 @@ PyAPI_FUNC(void) PyEval_RestoreThread(PyThreadState *);
PyAPI_FUNC(int) PyEval_ThreadsInitialized(void); PyAPI_FUNC(int) PyEval_ThreadsInitialized(void);
PyAPI_FUNC(void) PyEval_InitThreads(void); PyAPI_FUNC(void) PyEval_InitThreads(void);
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _PyEval_FiniThreads(void);
#endif /* !Py_LIMITED_API */
PyAPI_FUNC(void) PyEval_AcquireLock(void) Py_DEPRECATED(3.2); PyAPI_FUNC(void) PyEval_AcquireLock(void) Py_DEPRECATED(3.2);
PyAPI_FUNC(void) PyEval_ReleaseLock(void) /* Py_DEPRECATED(3.2) */; PyAPI_FUNC(void) PyEval_ReleaseLock(void) /* Py_DEPRECATED(3.2) */;
PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate); PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate);
...@@ -221,7 +217,6 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc); ...@@ -221,7 +217,6 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc);
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *); PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *); PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *);
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(void);
#endif #endif
/* Masks and values used by FORMAT_VALUE opcode. */ /* Masks and values used by FORMAT_VALUE opcode. */
......
...@@ -9,50 +9,21 @@ extern "C" { ...@@ -9,50 +9,21 @@ extern "C" {
#endif #endif
#include "pycore_atomic.h" #include "pycore_atomic.h"
#include "pycore_pystate.h"
#include "pythread.h" #include "pythread.h"
PyAPI_FUNC(void) _Py_FinishPendingCalls(void); PyAPI_FUNC(void) _Py_FinishPendingCalls(_PyRuntimeState *runtime);
struct _pending_calls {
int finishing;
PyThread_type_lock lock;
/* Request for running pending calls. */
_Py_atomic_int calls_to_do;
/* Request for looking at the `async_exc` field of the current
thread state.
Guarded by the GIL. */
int async_exc;
#define NPENDINGCALLS 32
struct {
int (*func)(void *);
void *arg;
} calls[NPENDINGCALLS];
int first;
int last;
};
#include "pycore_gil.h"
struct _ceval_runtime_state {
int recursion_limit;
/* Records whether tracing is on for any thread. Counts the number
of threads for which tstate->c_tracefunc is non-NULL, so if the
value is 0, we know we don't have to check this thread's
c_tracefunc. This speeds up the if statement in
PyEval_EvalFrameEx() after fast_next_opcode. */
int tracing_possible;
/* This single variable consolidates all requests to break out of
the fast path in the eval loop. */
_Py_atomic_int eval_breaker;
/* Request for dropping the GIL */
_Py_atomic_int gil_drop_request;
struct _pending_calls pending;
/* Request for checking signals. */
_Py_atomic_int signals_pending;
struct _gil_runtime_state gil;
};
PyAPI_FUNC(void) _PyEval_Initialize(struct _ceval_runtime_state *); PyAPI_FUNC(void) _PyEval_Initialize(struct _ceval_runtime_state *);
PyAPI_FUNC(void) _PyEval_FiniThreads(
struct _ceval_runtime_state *ceval);
PyAPI_FUNC(void) _PyEval_SignalReceived(
struct _ceval_runtime_state *ceval);
PyAPI_FUNC(int) _PyEval_AddPendingCall(
struct _ceval_runtime_state *ceval,
int (*func)(void *),
void *arg);
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(
struct _ceval_runtime_state *ceval);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
...@@ -12,12 +12,51 @@ extern "C" { ...@@ -12,12 +12,51 @@ extern "C" {
#include "pystate.h" #include "pystate.h"
#include "pythread.h" #include "pythread.h"
#include "pycore_ceval.h" #include "pycore_gil.h" /* _gil_runtime_state */
#include "pycore_pathconfig.h" #include "pycore_pathconfig.h"
#include "pycore_pymem.h" #include "pycore_pymem.h"
#include "pycore_warnings.h" #include "pycore_warnings.h"
/* ceval state */
struct _pending_calls {
int finishing;
PyThread_type_lock lock;
/* Request for running pending calls. */
_Py_atomic_int calls_to_do;
/* Request for looking at the `async_exc` field of the current
thread state.
Guarded by the GIL. */
int async_exc;
#define NPENDINGCALLS 32
struct {
int (*func)(void *);
void *arg;
} calls[NPENDINGCALLS];
int first;
int last;
};
struct _ceval_runtime_state {
int recursion_limit;
/* Records whether tracing is on for any thread. Counts the number
of threads for which tstate->c_tracefunc is non-NULL, so if the
value is 0, we know we don't have to check this thread's
c_tracefunc. This speeds up the if statement in
PyEval_EvalFrameEx() after fast_next_opcode. */
int tracing_possible;
/* This single variable consolidates all requests to break out of
the fast path in the eval loop. */
_Py_atomic_int eval_breaker;
/* Request for dropping the GIL */
_Py_atomic_int gil_drop_request;
struct _pending_calls pending;
/* Request for checking signals. */
_Py_atomic_int signals_pending;
struct _gil_runtime_state gil;
};
/* interpreter state */ /* interpreter state */
typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int); typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int);
...@@ -203,13 +242,16 @@ PyAPI_FUNC(_PyInitError) _PyRuntime_Initialize(void); ...@@ -203,13 +242,16 @@ PyAPI_FUNC(_PyInitError) _PyRuntime_Initialize(void);
PyAPI_FUNC(void) _PyRuntime_Finalize(void); PyAPI_FUNC(void) _PyRuntime_Finalize(void);
#define _Py_CURRENTLY_FINALIZING(tstate) \ #define _Py_CURRENTLY_FINALIZING(runtime, tstate) \
(_PyRuntime.finalizing == tstate) (runtime->finalizing == tstate)
/* Variable and macro for in-line access to current thread /* Variable and macro for in-line access to current thread
and interpreter state */ and interpreter state */
#define _PyRuntimeState_GetThreadState(runtime) \
((PyThreadState*)_Py_atomic_load_relaxed(&(runtime)->gilstate.tstate_current))
/* Get the current Python thread state. /* Get the current Python thread state.
Efficient macro reading directly the 'gilstate.tstate_current' atomic Efficient macro reading directly the 'gilstate.tstate_current' atomic
...@@ -219,8 +261,7 @@ PyAPI_FUNC(void) _PyRuntime_Finalize(void); ...@@ -219,8 +261,7 @@ PyAPI_FUNC(void) _PyRuntime_Finalize(void);
The caller must hold the GIL. The caller must hold the GIL.
See also PyThreadState_Get() and PyThreadState_GET(). */ See also PyThreadState_Get() and PyThreadState_GET(). */
#define _PyThreadState_GET() \ #define _PyThreadState_GET() _PyRuntimeState_GetThreadState(&_PyRuntime)
((PyThreadState*)_Py_atomic_load_relaxed(&_PyRuntime.gilstate.tstate_current))
/* Redefine PyThreadState_GET() as an alias to _PyThreadState_GET() */ /* Redefine PyThreadState_GET() as an alias to _PyThreadState_GET() */
#undef PyThreadState_GET #undef PyThreadState_GET
...@@ -242,7 +283,13 @@ PyAPI_FUNC(void) _PyRuntime_Finalize(void); ...@@ -242,7 +283,13 @@ PyAPI_FUNC(void) _PyRuntime_Finalize(void);
PyAPI_FUNC(void) _PyThreadState_Init( PyAPI_FUNC(void) _PyThreadState_Init(
_PyRuntimeState *runtime, _PyRuntimeState *runtime,
PyThreadState *tstate); PyThreadState *tstate);
PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept(
_PyRuntimeState *runtime,
PyThreadState *tstate);
PyAPI_FUNC(PyThreadState *) _PyThreadState_Swap(
struct _gilstate_runtime_state *gilstate,
PyThreadState *newts);
PyAPI_FUNC(_PyInitError) _PyInterpreterState_Enable(_PyRuntimeState *runtime); PyAPI_FUNC(_PyInitError) _PyInterpreterState_Enable(_PyRuntimeState *runtime);
PyAPI_FUNC(void) _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime); PyAPI_FUNC(void) _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime);
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "Python.h" #include "Python.h"
#include "pycore_atomic.h" #include "pycore_atomic.h"
#include "pycore_ceval.h"
#include "pycore_pystate.h"
#ifndef MS_WINDOWS #ifndef MS_WINDOWS
#include "posixmodule.h" #include "posixmodule.h"
...@@ -256,7 +258,8 @@ trip_signal(int sig_num) ...@@ -256,7 +258,8 @@ trip_signal(int sig_num)
_Py_atomic_store(&is_tripped, 1); _Py_atomic_store(&is_tripped, 1);
/* Notify ceval.c */ /* Notify ceval.c */
_PyEval_SignalReceived(); _PyRuntimeState *runtime = &_PyRuntime;
_PyEval_SignalReceived(&runtime->ceval);
/* And then write to the wakeup fd *after* setting all the globals and /* And then write to the wakeup fd *after* setting all the globals and
doing the _PyEval_SignalReceived. We used to write to the wakeup fd doing the _PyEval_SignalReceived. We used to write to the wakeup fd
...@@ -296,7 +299,8 @@ trip_signal(int sig_num) ...@@ -296,7 +299,8 @@ trip_signal(int sig_num)
{ {
/* Py_AddPendingCall() isn't signal-safe, but we /* Py_AddPendingCall() isn't signal-safe, but we
still use it for this exceptional case. */ still use it for this exceptional case. */
Py_AddPendingCall(report_wakeup_send_error, _PyEval_AddPendingCall(&runtime->ceval,
report_wakeup_send_error,
(void *)(intptr_t) last_error); (void *)(intptr_t) last_error);
} }
} }
...@@ -314,7 +318,8 @@ trip_signal(int sig_num) ...@@ -314,7 +318,8 @@ trip_signal(int sig_num)
{ {
/* Py_AddPendingCall() isn't signal-safe, but we /* Py_AddPendingCall() isn't signal-safe, but we
still use it for this exceptional case. */ still use it for this exceptional case. */
Py_AddPendingCall(report_wakeup_write_error, _PyEval_AddPendingCall(&runtime->ceval,
report_wakeup_write_error,
(void *)(intptr_t)errno); (void *)(intptr_t)errno);
} }
} }
......
This diff is collapsed.
...@@ -7,10 +7,6 @@ ...@@ -7,10 +7,6 @@
#include "pycore_atomic.h" #include "pycore_atomic.h"
/* First some general settings */
#define INTERVAL (_PyRuntime.ceval.gil.interval >= 1 ? _PyRuntime.ceval.gil.interval : 1)
/* /*
Notes about the implementation: Notes about the implementation:
...@@ -94,158 +90,156 @@ ...@@ -94,158 +90,156 @@
#define DEFAULT_INTERVAL 5000 #define DEFAULT_INTERVAL 5000
static void _gil_initialize(struct _gil_runtime_state *state) static void _gil_initialize(struct _gil_runtime_state *gil)
{ {
_Py_atomic_int uninitialized = {-1}; _Py_atomic_int uninitialized = {-1};
state->locked = uninitialized; gil->locked = uninitialized;
state->interval = DEFAULT_INTERVAL; gil->interval = DEFAULT_INTERVAL;
} }
static int gil_created(void) static int gil_created(struct _gil_runtime_state *gil)
{ {
return (_Py_atomic_load_explicit(&_PyRuntime.ceval.gil.locked, return (_Py_atomic_load_explicit(&gil->locked, _Py_memory_order_acquire) >= 0);
_Py_memory_order_acquire)
) >= 0;
} }
static void create_gil(void) static void create_gil(struct _gil_runtime_state *gil)
{ {
MUTEX_INIT(_PyRuntime.ceval.gil.mutex); MUTEX_INIT(gil->mutex);
#ifdef FORCE_SWITCHING #ifdef FORCE_SWITCHING
MUTEX_INIT(_PyRuntime.ceval.gil.switch_mutex); MUTEX_INIT(gil->switch_mutex);
#endif #endif
COND_INIT(_PyRuntime.ceval.gil.cond); COND_INIT(gil->cond);
#ifdef FORCE_SWITCHING #ifdef FORCE_SWITCHING
COND_INIT(_PyRuntime.ceval.gil.switch_cond); COND_INIT(gil->switch_cond);
#endif #endif
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.last_holder, 0); _Py_atomic_store_relaxed(&gil->last_holder, 0);
_Py_ANNOTATE_RWLOCK_CREATE(&_PyRuntime.ceval.gil.locked); _Py_ANNOTATE_RWLOCK_CREATE(&gil->locked);
_Py_atomic_store_explicit(&_PyRuntime.ceval.gil.locked, 0, _Py_atomic_store_explicit(&gil->locked, 0, _Py_memory_order_release);
_Py_memory_order_release);
} }
static void destroy_gil(void) static void destroy_gil(struct _gil_runtime_state *gil)
{ {
/* some pthread-like implementations tie the mutex to the cond /* some pthread-like implementations tie the mutex to the cond
* and must have the cond destroyed first. * and must have the cond destroyed first.
*/ */
COND_FINI(_PyRuntime.ceval.gil.cond); COND_FINI(gil->cond);
MUTEX_FINI(_PyRuntime.ceval.gil.mutex); MUTEX_FINI(gil->mutex);
#ifdef FORCE_SWITCHING #ifdef FORCE_SWITCHING
COND_FINI(_PyRuntime.ceval.gil.switch_cond); COND_FINI(gil->switch_cond);
MUTEX_FINI(_PyRuntime.ceval.gil.switch_mutex); MUTEX_FINI(gil->switch_mutex);
#endif #endif
_Py_atomic_store_explicit(&_PyRuntime.ceval.gil.locked, -1, _Py_atomic_store_explicit(&gil->locked, -1,
_Py_memory_order_release); _Py_memory_order_release);
_Py_ANNOTATE_RWLOCK_DESTROY(&_PyRuntime.ceval.gil.locked); _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked);
} }
static void recreate_gil(void) static void recreate_gil(struct _gil_runtime_state *gil)
{ {
_Py_ANNOTATE_RWLOCK_DESTROY(&_PyRuntime.ceval.gil.locked); _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked);
/* XXX should we destroy the old OS resources here? */ /* XXX should we destroy the old OS resources here? */
create_gil(); create_gil(gil);
} }
static void drop_gil(PyThreadState *tstate) static void
drop_gil(struct _ceval_runtime_state *ceval, PyThreadState *tstate)
{ {
if (!_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked)) struct _gil_runtime_state *gil = &ceval->gil;
if (!_Py_atomic_load_relaxed(&gil->locked)) {
Py_FatalError("drop_gil: GIL is not locked"); Py_FatalError("drop_gil: GIL is not locked");
}
/* tstate is allowed to be NULL (early interpreter init) */ /* tstate is allowed to be NULL (early interpreter init) */
if (tstate != NULL) { if (tstate != NULL) {
/* Sub-interpreter support: threads might have been switched /* Sub-interpreter support: threads might have been switched
under our feet using PyThreadState_Swap(). Fix the GIL last under our feet using PyThreadState_Swap(). Fix the GIL last
holder variable so that our heuristics work. */ holder variable so that our heuristics work. */
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.last_holder, _Py_atomic_store_relaxed(&gil->last_holder, (uintptr_t)tstate);
(uintptr_t)tstate);
} }
MUTEX_LOCK(_PyRuntime.ceval.gil.mutex); MUTEX_LOCK(gil->mutex);
_Py_ANNOTATE_RWLOCK_RELEASED(&_PyRuntime.ceval.gil.locked, /*is_write=*/1); _Py_ANNOTATE_RWLOCK_RELEASED(&gil->locked, /*is_write=*/1);
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.locked, 0); _Py_atomic_store_relaxed(&gil->locked, 0);
COND_SIGNAL(_PyRuntime.ceval.gil.cond); COND_SIGNAL(gil->cond);
MUTEX_UNLOCK(_PyRuntime.ceval.gil.mutex); MUTEX_UNLOCK(gil->mutex);
#ifdef FORCE_SWITCHING #ifdef FORCE_SWITCHING
if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request) && if (_Py_atomic_load_relaxed(&ceval->gil_drop_request) && tstate != NULL) {
tstate != NULL) MUTEX_LOCK(gil->switch_mutex);
{
MUTEX_LOCK(_PyRuntime.ceval.gil.switch_mutex);
/* Not switched yet => wait */ /* Not switched yet => wait */
if (((PyThreadState*)_Py_atomic_load_relaxed( if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) == tstate)
&_PyRuntime.ceval.gil.last_holder)
) == tstate)
{ {
RESET_GIL_DROP_REQUEST(); RESET_GIL_DROP_REQUEST(ceval);
/* NOTE: if COND_WAIT does not atomically start waiting when /* NOTE: if COND_WAIT does not atomically start waiting when
releasing the mutex, another thread can run through, take releasing the mutex, another thread can run through, take
the GIL and drop it again, and reset the condition the GIL and drop it again, and reset the condition
before we even had a chance to wait for it. */ before we even had a chance to wait for it. */
COND_WAIT(_PyRuntime.ceval.gil.switch_cond, COND_WAIT(gil->switch_cond, gil->switch_mutex);
_PyRuntime.ceval.gil.switch_mutex);
} }
MUTEX_UNLOCK(_PyRuntime.ceval.gil.switch_mutex); MUTEX_UNLOCK(gil->switch_mutex);
} }
#endif #endif
} }
static void take_gil(PyThreadState *tstate) static void
take_gil(struct _ceval_runtime_state *ceval, PyThreadState *tstate)
{ {
int err; if (tstate == NULL) {
if (tstate == NULL)
Py_FatalError("take_gil: NULL tstate"); Py_FatalError("take_gil: NULL tstate");
}
err = errno; struct _gil_runtime_state *gil = &ceval->gil;
MUTEX_LOCK(_PyRuntime.ceval.gil.mutex); int err = errno;
MUTEX_LOCK(gil->mutex);
if (!_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked)) if (!_Py_atomic_load_relaxed(&gil->locked)) {
goto _ready; goto _ready;
}
while (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked)) { while (_Py_atomic_load_relaxed(&gil->locked)) {
int timed_out = 0; int timed_out = 0;
unsigned long saved_switchnum; unsigned long saved_switchnum;
saved_switchnum = _PyRuntime.ceval.gil.switch_number; saved_switchnum = gil->switch_number;
COND_TIMED_WAIT(_PyRuntime.ceval.gil.cond, _PyRuntime.ceval.gil.mutex,
INTERVAL, timed_out);
unsigned long interval = (gil->interval >= 1 ? gil->interval : 1);
COND_TIMED_WAIT(gil->cond, gil->mutex, interval, timed_out);
/* If we timed out and no switch occurred in the meantime, it is time /* If we timed out and no switch occurred in the meantime, it is time
to ask the GIL-holding thread to drop it. */ to ask the GIL-holding thread to drop it. */
if (timed_out && if (timed_out &&
_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked) && _Py_atomic_load_relaxed(&gil->locked) &&
_PyRuntime.ceval.gil.switch_number == saved_switchnum) { gil->switch_number == saved_switchnum)
SET_GIL_DROP_REQUEST(); {
SET_GIL_DROP_REQUEST(ceval);
} }
} }
_ready: _ready:
#ifdef FORCE_SWITCHING #ifdef FORCE_SWITCHING
/* This mutex must be taken before modifying /* This mutex must be taken before modifying gil->last_holder:
_PyRuntime.ceval.gil.last_holder (see drop_gil()). */ see drop_gil(). */
MUTEX_LOCK(_PyRuntime.ceval.gil.switch_mutex); MUTEX_LOCK(gil->switch_mutex);
#endif #endif
/* We now hold the GIL */ /* We now hold the GIL */
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.locked, 1); _Py_atomic_store_relaxed(&gil->locked, 1);
_Py_ANNOTATE_RWLOCK_ACQUIRED(&_PyRuntime.ceval.gil.locked, /*is_write=*/1); _Py_ANNOTATE_RWLOCK_ACQUIRED(&gil->locked, /*is_write=*/1);
if (tstate != (PyThreadState*)_Py_atomic_load_relaxed( if (tstate != (PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) {
&_PyRuntime.ceval.gil.last_holder)) _Py_atomic_store_relaxed(&gil->last_holder, (uintptr_t)tstate);
{ ++gil->switch_number;
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil.last_holder,
(uintptr_t)tstate);
++_PyRuntime.ceval.gil.switch_number;
} }
#ifdef FORCE_SWITCHING #ifdef FORCE_SWITCHING
COND_SIGNAL(_PyRuntime.ceval.gil.switch_cond); COND_SIGNAL(gil->switch_cond);
MUTEX_UNLOCK(_PyRuntime.ceval.gil.switch_mutex); MUTEX_UNLOCK(gil->switch_mutex);
#endif #endif
if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request)) { if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) {
RESET_GIL_DROP_REQUEST(); RESET_GIL_DROP_REQUEST(ceval);
} }
if (tstate->async_exc != NULL) { if (tstate->async_exc != NULL) {
_PyEval_SignalAsyncExc(); _PyEval_SignalAsyncExc(ceval);
} }
MUTEX_UNLOCK(_PyRuntime.ceval.gil.mutex); MUTEX_UNLOCK(gil->mutex);
errno = err; errno = err;
} }
......
...@@ -4,8 +4,9 @@ ...@@ -4,8 +4,9 @@
#include "Python-ast.h" #include "Python-ast.h"
#undef Yield /* undefine macro conflicting with <winbase.h> */ #undef Yield /* undefine macro conflicting with <winbase.h> */
#include "pycore_coreconfig.h" #include "pycore_ceval.h"
#include "pycore_context.h" #include "pycore_context.h"
#include "pycore_coreconfig.h"
#include "pycore_fileutils.h" #include "pycore_fileutils.h"
#include "pycore_hamt.h" #include "pycore_hamt.h"
#include "pycore_pathconfig.h" #include "pycore_pathconfig.h"
...@@ -527,7 +528,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime, ...@@ -527,7 +528,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
another running thread (see issue #9901). another running thread (see issue #9901).
Instead we destroy the previously created GIL here, which ensures Instead we destroy the previously created GIL here, which ensures
that we can call Py_Initialize / Py_FinalizeEx multiple times. */ that we can call Py_Initialize / Py_FinalizeEx multiple times. */
_PyEval_FiniThreads(); _PyEval_FiniThreads(&runtime->ceval);
/* Auto-thread-state API */ /* Auto-thread-state API */
_PyGILState_Init(runtime, interp, tstate); _PyGILState_Init(runtime, interp, tstate);
...@@ -1135,10 +1136,10 @@ Py_FinalizeEx(void) ...@@ -1135,10 +1136,10 @@ Py_FinalizeEx(void)
wait_for_thread_shutdown(); wait_for_thread_shutdown();
// Make any remaining pending calls. // Make any remaining pending calls.
_Py_FinishPendingCalls(); _Py_FinishPendingCalls(runtime);
/* Get current thread state and interpreter pointer */ /* Get current thread state and interpreter pointer */
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
PyInterpreterState *interp = tstate->interp; PyInterpreterState *interp = tstate->interp;
/* The interpreter is still entirely intact at this point, and the /* The interpreter is still entirely intact at this point, and the
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
/* Thread and interpreter state structures and their interfaces */ /* Thread and interpreter state structures and their interfaces */
#include "Python.h" #include "Python.h"
#include "pycore_ceval.h"
#include "pycore_coreconfig.h" #include "pycore_coreconfig.h"
#include "pycore_pymem.h" #include "pycore_pymem.h"
#include "pycore_pystate.h" #include "pycore_pystate.h"
...@@ -39,7 +40,6 @@ extern "C" { ...@@ -39,7 +40,6 @@ extern "C" {
/* Forward declarations */ /* Forward declarations */
static PyThreadState *_PyGILState_GetThisThreadState(struct _gilstate_runtime_state *gilstate); static PyThreadState *_PyGILState_GetThisThreadState(struct _gilstate_runtime_state *gilstate);
static void _PyThreadState_Delete(_PyRuntimeState *runtime, PyThreadState *tstate); static void _PyThreadState_Delete(_PyRuntimeState *runtime, PyThreadState *tstate);
static PyThreadState *_PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *newts);
static _PyInitError static _PyInitError
...@@ -867,9 +867,8 @@ PyThreadState_DeleteCurrent() ...@@ -867,9 +867,8 @@ PyThreadState_DeleteCurrent()
* be kept in those other interpreteres. * be kept in those other interpreteres.
*/ */
void void
_PyThreadState_DeleteExcept(PyThreadState *tstate) _PyThreadState_DeleteExcept(_PyRuntimeState *runtime, PyThreadState *tstate)
{ {
_PyRuntimeState *runtime = &_PyRuntime;
PyInterpreterState *interp = tstate->interp; PyInterpreterState *interp = tstate->interp;
PyThreadState *p, *next, *garbage; PyThreadState *p, *next, *garbage;
HEAD_LOCK(runtime); HEAD_LOCK(runtime);
...@@ -915,7 +914,7 @@ PyThreadState_Get(void) ...@@ -915,7 +914,7 @@ PyThreadState_Get(void)
} }
static PyThreadState * PyThreadState *
_PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *newts) _PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *newts)
{ {
PyThreadState *oldts = _PyRuntimeGILState_GetThreadState(gilstate); PyThreadState *oldts = _PyRuntimeGILState_GetThreadState(gilstate);
...@@ -980,8 +979,8 @@ PyThreadState_GetDict(void) ...@@ -980,8 +979,8 @@ PyThreadState_GetDict(void)
int int
PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
{ {
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE(); _PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *p; PyInterpreterState *interp = _PyRuntimeState_GetThreadState(runtime)->interp;
/* Although the GIL is held, a few C API functions can be called /* Although the GIL is held, a few C API functions can be called
* without the GIL held, and in particular some that create and * without the GIL held, and in particular some that create and
...@@ -989,9 +988,8 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) ...@@ -989,9 +988,8 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
* list of thread states we're traversing, so to prevent that we lock * list of thread states we're traversing, so to prevent that we lock
* head_mutex for the duration. * head_mutex for the duration.
*/ */
_PyRuntimeState *runtime = &_PyRuntime;
HEAD_LOCK(runtime); HEAD_LOCK(runtime);
for (p = interp->tstate_head; p != NULL; p = p->next) { for (PyThreadState *p = interp->tstate_head; p != NULL; p = p->next) {
if (p->thread_id == id) { if (p->thread_id == id) {
/* Tricky: we need to decref the current value /* Tricky: we need to decref the current value
* (if any) in p->async_exc, but that can in turn * (if any) in p->async_exc, but that can in turn
...@@ -1005,7 +1003,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) ...@@ -1005,7 +1003,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
p->async_exc = exc; p->async_exc = exc;
HEAD_UNLOCK(runtime); HEAD_UNLOCK(runtime);
Py_XDECREF(old_exc); Py_XDECREF(old_exc);
_PyEval_SignalAsyncExc(); _PyEval_SignalAsyncExc(&runtime->ceval);
return 1; return 1;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment