Skip to content

Commit 8849e59

Browse files
authored
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.
1 parent 1c60567 commit 8849e59

File tree

3 files changed

+19
-13
lines changed

3 files changed

+19
-13
lines changed

Include/internal/pycore_ceval.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ extern void _Py_FinishPendingCalls(PyThreadState *tstate);
1919
extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *);
2020
extern void _PyEval_InitState(struct _ceval_state *);
2121
extern void _PyEval_FiniThreads(PyThreadState *tstate);
22-
PyAPI_FUNC(void) _PyEval_SignalReceived(
23-
struct _ceval_runtime_state *ceval);
22+
PyAPI_FUNC(void) _PyEval_SignalReceived(PyThreadState *tstate);
2423
PyAPI_FUNC(int) _PyEval_AddPendingCall(
2524
PyThreadState *tstate,
26-
struct _ceval_runtime_state *ceval,
2725
int (*func)(void *),
2826
void *arg);
2927
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyThreadState *tstate);

Modules/signalmodule.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,14 @@ trip_signal(int sig_num)
259259
cleared in PyErr_CheckSignals() before .tripped. */
260260
_Py_atomic_store(&is_tripped, 1);
261261

262+
/* Get the Python thread state using PyGILState API, since
263+
_PyThreadState_GET() returns NULL if the GIL is released.
264+
For example, signal.raise_signal() releases the GIL. */
265+
PyThreadState *tstate = PyGILState_GetThisThreadState();
266+
assert(tstate != NULL);
267+
262268
/* Notify ceval.c */
263-
_PyRuntimeState *runtime = &_PyRuntime;
264-
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
265-
_PyEval_SignalReceived(&runtime->ceval);
269+
_PyEval_SignalReceived(tstate);
266270

267271
/* And then write to the wakeup fd *after* setting all the globals and
268272
doing the _PyEval_SignalReceived. We used to write to the wakeup fd
@@ -302,7 +306,7 @@ trip_signal(int sig_num)
302306
{
303307
/* Py_AddPendingCall() isn't signal-safe, but we
304308
still use it for this exceptional case. */
305-
_PyEval_AddPendingCall(tstate, &runtime->ceval,
309+
_PyEval_AddPendingCall(tstate,
306310
report_wakeup_send_error,
307311
(void *)(intptr_t) last_error);
308312
}
@@ -321,7 +325,7 @@ trip_signal(int sig_num)
321325
{
322326
/* Py_AddPendingCall() isn't signal-safe, but we
323327
still use it for this exceptional case. */
324-
_PyEval_AddPendingCall(tstate, &runtime->ceval,
328+
_PyEval_AddPendingCall(tstate,
325329
report_wakeup_write_error,
326330
(void *)(intptr_t)errno);
327331
}

Python/ceval.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,9 @@ PyEval_RestoreThread(PyThreadState *tstate)
436436
*/
437437

438438
void
439-
_PyEval_SignalReceived(struct _ceval_runtime_state *ceval)
439+
_PyEval_SignalReceived(PyThreadState *tstate)
440440
{
441+
struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
441442
/* bpo-30703: Function called when the C signal handler of Python gets a
442443
signal. We cannot queue a callback using Py_AddPendingCall() since
443444
that function is not async-signal-safe. */
@@ -482,9 +483,9 @@ _pop_pending_call(struct _pending_calls *pending,
482483

483484
int
484485
_PyEval_AddPendingCall(PyThreadState *tstate,
485-
struct _ceval_runtime_state *ceval,
486486
int (*func)(void *), void *arg)
487487
{
488+
struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
488489
struct _pending_calls *pending = &ceval->pending;
489490

490491
PyThread_acquire_lock(pending->lock, WAIT_LOCK);
@@ -511,9 +512,12 @@ _PyEval_AddPendingCall(PyThreadState *tstate,
511512
int
512513
Py_AddPendingCall(int (*func)(void *), void *arg)
513514
{
514-
_PyRuntimeState *runtime = &_PyRuntime;
515-
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
516-
return _PyEval_AddPendingCall(tstate, &runtime->ceval, func, arg);
515+
/* Get the Python thread state using PyGILState API, since
516+
_PyThreadState_GET() returns NULL if the GIL is released.
517+
Py_AddPendingCall() doesn't require the caller to hold the GIL. */
518+
PyThreadState *tstate = PyGILState_GetThisThreadState();
519+
assert(tstate != NULL);
520+
return _PyEval_AddPendingCall(tstate, func, arg);
517521
}
518522

519523
static int

0 commit comments

Comments
 (0)