diff options
author | Victor Stinner <vstinner@python.org> | 2020-03-18 18:28:53 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-18 18:28:53 (GMT) |
commit | 8849e5962ba481d5d414b3467a256aba2134b4da (patch) | |
tree | 469b2d1023971843ce4e29f88ecbc8503342830f | |
parent | 1c60567b9a4c8f77e730de9d22690d8e68d7e5f6 (diff) | |
download | cpython-8849e5962ba481d5d414b3467a256aba2134b4da.zip cpython-8849e5962ba481d5d414b3467a256aba2134b4da.tar.gz cpython-8849e5962ba481d5d414b3467a256aba2134b4da.tar.bz2 |
bpo-39984: trip_signal() uses PyGILState_GetThisThreadState() (GH-19061)
bpo-37127, bpo-39984:
* trip_signal() and Py_AddPendingCall() now get the current Python
thread state using PyGILState_GetThisThreadState() rather than
_PyRuntimeState_GetThreadState() to be able to get it even if the
GIL is released.
* _PyEval_SignalReceived() now expects tstate rather than ceval.
* Remove ceval parameter of _PyEval_AddPendingCall(): ceval is now
get from tstate parameter.
-rw-r--r-- | Include/internal/pycore_ceval.h | 4 | ||||
-rw-r--r-- | Modules/signalmodule.c | 14 | ||||
-rw-r--r-- | Python/ceval.c | 14 |
3 files changed, 19 insertions, 13 deletions
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 4e5ae17..ccfb9ab 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -19,11 +19,9 @@ extern void _Py_FinishPendingCalls(PyThreadState *tstate); extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *); extern void _PyEval_InitState(struct _ceval_state *); extern void _PyEval_FiniThreads(PyThreadState *tstate); -PyAPI_FUNC(void) _PyEval_SignalReceived( - struct _ceval_runtime_state *ceval); +PyAPI_FUNC(void) _PyEval_SignalReceived(PyThreadState *tstate); PyAPI_FUNC(int) _PyEval_AddPendingCall( PyThreadState *tstate, - struct _ceval_runtime_state *ceval, int (*func)(void *), void *arg); PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyThreadState *tstate); diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index a197673..1028531 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -259,10 +259,14 @@ trip_signal(int sig_num) cleared in PyErr_CheckSignals() before .tripped. */ _Py_atomic_store(&is_tripped, 1); + /* Get the Python thread state using PyGILState API, since + _PyThreadState_GET() returns NULL if the GIL is released. + For example, signal.raise_signal() releases the GIL. */ + PyThreadState *tstate = PyGILState_GetThisThreadState(); + assert(tstate != NULL); + /* Notify ceval.c */ - _PyRuntimeState *runtime = &_PyRuntime; - PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); - _PyEval_SignalReceived(&runtime->ceval); + _PyEval_SignalReceived(tstate); /* 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 @@ -302,7 +306,7 @@ trip_signal(int sig_num) { /* Py_AddPendingCall() isn't signal-safe, but we still use it for this exceptional case. */ - _PyEval_AddPendingCall(tstate, &runtime->ceval, + _PyEval_AddPendingCall(tstate, report_wakeup_send_error, (void *)(intptr_t) last_error); } @@ -321,7 +325,7 @@ trip_signal(int sig_num) { /* Py_AddPendingCall() isn't signal-safe, but we still use it for this exceptional case. */ - _PyEval_AddPendingCall(tstate, &runtime->ceval, + _PyEval_AddPendingCall(tstate, report_wakeup_write_error, (void *)(intptr_t)errno); } diff --git a/Python/ceval.c b/Python/ceval.c index 8958e14..2f65ea2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -436,8 +436,9 @@ PyEval_RestoreThread(PyThreadState *tstate) */ void -_PyEval_SignalReceived(struct _ceval_runtime_state *ceval) +_PyEval_SignalReceived(PyThreadState *tstate) { + struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval; /* bpo-30703: Function called when the C signal handler of Python gets a signal. We cannot queue a callback using Py_AddPendingCall() since that function is not async-signal-safe. */ @@ -482,9 +483,9 @@ _pop_pending_call(struct _pending_calls *pending, int _PyEval_AddPendingCall(PyThreadState *tstate, - struct _ceval_runtime_state *ceval, int (*func)(void *), void *arg) { + struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval; struct _pending_calls *pending = &ceval->pending; PyThread_acquire_lock(pending->lock, WAIT_LOCK); @@ -511,9 +512,12 @@ _PyEval_AddPendingCall(PyThreadState *tstate, int Py_AddPendingCall(int (*func)(void *), void *arg) { - _PyRuntimeState *runtime = &_PyRuntime; - PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); - return _PyEval_AddPendingCall(tstate, &runtime->ceval, func, arg); + /* Get the Python thread state using PyGILState API, since + _PyThreadState_GET() returns NULL if the GIL is released. + Py_AddPendingCall() doesn't require the caller to hold the GIL. */ + PyThreadState *tstate = PyGILState_GetThisThreadState(); + assert(tstate != NULL); + return _PyEval_AddPendingCall(tstate, func, arg); } static int |