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.
This commit is contained in:
Victor Stinner 2020-03-18 19:28:53 +01:00 committed by GitHub
parent 1c60567b9a
commit 8849e5962b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 13 deletions

View file

@ -19,11 +19,9 @@ extern void _Py_FinishPendingCalls(PyThreadState *tstate);
extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *); extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *);
extern void _PyEval_InitState(struct _ceval_state *); extern void _PyEval_InitState(struct _ceval_state *);
extern void _PyEval_FiniThreads(PyThreadState *tstate); extern void _PyEval_FiniThreads(PyThreadState *tstate);
PyAPI_FUNC(void) _PyEval_SignalReceived( PyAPI_FUNC(void) _PyEval_SignalReceived(PyThreadState *tstate);
struct _ceval_runtime_state *ceval);
PyAPI_FUNC(int) _PyEval_AddPendingCall( PyAPI_FUNC(int) _PyEval_AddPendingCall(
PyThreadState *tstate, PyThreadState *tstate,
struct _ceval_runtime_state *ceval,
int (*func)(void *), int (*func)(void *),
void *arg); void *arg);
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyThreadState *tstate); PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyThreadState *tstate);

View file

@ -259,10 +259,14 @@ trip_signal(int sig_num)
cleared in PyErr_CheckSignals() before .tripped. */ cleared in PyErr_CheckSignals() before .tripped. */
_Py_atomic_store(&is_tripped, 1); _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 */ /* Notify ceval.c */
_PyRuntimeState *runtime = &_PyRuntime; _PyEval_SignalReceived(tstate);
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
_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
@ -302,7 +306,7 @@ 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. */
_PyEval_AddPendingCall(tstate, &runtime->ceval, _PyEval_AddPendingCall(tstate,
report_wakeup_send_error, report_wakeup_send_error,
(void *)(intptr_t) last_error); (void *)(intptr_t) last_error);
} }
@ -321,7 +325,7 @@ 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. */
_PyEval_AddPendingCall(tstate, &runtime->ceval, _PyEval_AddPendingCall(tstate,
report_wakeup_write_error, report_wakeup_write_error,
(void *)(intptr_t)errno); (void *)(intptr_t)errno);
} }

View file

@ -436,8 +436,9 @@ PyEval_RestoreThread(PyThreadState *tstate)
*/ */
void 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 /* bpo-30703: Function called when the C signal handler of Python gets a
signal. We cannot queue a callback using Py_AddPendingCall() since signal. We cannot queue a callback using Py_AddPendingCall() since
that function is not async-signal-safe. */ that function is not async-signal-safe. */
@ -482,9 +483,9 @@ _pop_pending_call(struct _pending_calls *pending,
int int
_PyEval_AddPendingCall(PyThreadState *tstate, _PyEval_AddPendingCall(PyThreadState *tstate,
struct _ceval_runtime_state *ceval,
int (*func)(void *), void *arg) int (*func)(void *), void *arg)
{ {
struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
struct _pending_calls *pending = &ceval->pending; struct _pending_calls *pending = &ceval->pending;
PyThread_acquire_lock(pending->lock, WAIT_LOCK); PyThread_acquire_lock(pending->lock, WAIT_LOCK);
@ -511,9 +512,12 @@ _PyEval_AddPendingCall(PyThreadState *tstate,
int int
Py_AddPendingCall(int (*func)(void *), void *arg) Py_AddPendingCall(int (*func)(void *), void *arg)
{ {
_PyRuntimeState *runtime = &_PyRuntime; /* Get the Python thread state using PyGILState API, since
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); _PyThreadState_GET() returns NULL if the GIL is released.
return _PyEval_AddPendingCall(tstate, &runtime->ceval, func, arg); 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 static int