Skip to content

Commit b54a99d

Browse files
authored
bpo-40082: trip_signal() uses the main interpreter (GH-19441)
Fix the signal handler: it now always uses the main interpreter, rather than trying to get the current Python thread state. The following function now accepts an interpreter, instead of a Python thread state: * _PyEval_SignalReceived() * _Py_ThreadCanHandleSignals() * _PyEval_AddPendingCall() * COMPUTE_EVAL_BREAKER() * SET_GIL_DROP_REQUEST(), RESET_GIL_DROP_REQUEST() * SIGNAL_PENDING_CALLS(), UNSIGNAL_PENDING_CALLS() * SIGNAL_PENDING_SIGNALS(), UNSIGNAL_PENDING_SIGNALS() * SIGNAL_ASYNC_EXC(), UNSIGNAL_ASYNC_EXC() Py_AddPendingCall() now uses the main interpreter if it fails to the current Python thread state. Convert _PyThreadState_GET() and PyInterpreterState_GET_UNSAFE() macros to static inline functions.
1 parent cfc3c2f commit b54a99d

File tree

6 files changed

+94
-85
lines changed

6 files changed

+94
-85
lines changed

Include/internal/pycore_ceval.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ extern void _Py_FinishPendingCalls(PyThreadState *tstate);
1919
extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *);
2020
extern int _PyEval_InitState(struct _ceval_state *ceval);
2121
extern void _PyEval_FiniState(struct _ceval_state *ceval);
22-
PyAPI_FUNC(void) _PyEval_SignalReceived(PyThreadState *tstate);
22+
PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp);
2323
PyAPI_FUNC(int) _PyEval_AddPendingCall(
24-
PyThreadState *tstate,
24+
PyInterpreterState *interp,
2525
int (*func)(void *),
2626
void *arg);
2727
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyThreadState *tstate);

Include/internal/pycore_pystate.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,9 @@ _Py_IsMainInterpreter(PyThreadState* tstate)
310310

311311
/* Only handle signals on the main thread of the main interpreter. */
312312
static inline int
313-
_Py_ThreadCanHandleSignals(PyThreadState *tstate)
313+
_Py_ThreadCanHandleSignals(PyInterpreterState *interp)
314314
{
315-
return (_Py_IsMainThread() && _Py_IsMainInterpreter(tstate));
315+
return (_Py_IsMainThread() && interp == _PyRuntime.interpreters.main);
316316
}
317317

318318

@@ -340,7 +340,9 @@ static inline PyThreadState* _PyRuntimeState_GetThreadState(_PyRuntimeState *run
340340
The caller must hold the GIL.
341341
342342
See also PyThreadState_Get() and PyThreadState_GET(). */
343-
#define _PyThreadState_GET() _PyRuntimeState_GetThreadState(&_PyRuntime)
343+
static inline PyThreadState *_PyThreadState_GET(void) {
344+
return _PyRuntimeState_GetThreadState(&_PyRuntime);
345+
}
344346

345347
/* Redefine PyThreadState_GET() as an alias to _PyThreadState_GET() */
346348
#undef PyThreadState_GET
@@ -354,7 +356,10 @@ static inline PyThreadState* _PyRuntimeState_GetThreadState(_PyRuntimeState *run
354356
355357
See also _PyInterpreterState_Get()
356358
and _PyGILState_GetInterpreterStateUnsafe(). */
357-
#define _PyInterpreterState_GET_UNSAFE() (_PyThreadState_GET()->interp)
359+
static inline PyInterpreterState* _PyInterpreterState_GET_UNSAFE(void) {
360+
PyThreadState *tstate = _PyThreadState_GET();
361+
return tstate->interp;
362+
}
358363

359364

360365
/* Other */
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix the signal handler: it now always uses the main interpreter, rather than
2+
trying to get the current Python thread state.

Modules/signalmodule.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -252,14 +252,11 @@ trip_signal(int sig_num)
252252
cleared in PyErr_CheckSignals() before .tripped. */
253253
_Py_atomic_store(&is_tripped, 1);
254254

255-
/* Get the Python thread state using PyGILState API, since
256-
_PyThreadState_GET() returns NULL if the GIL is released.
257-
For example, signal.raise_signal() releases the GIL. */
258-
PyThreadState *tstate = PyGILState_GetThisThreadState();
259-
assert(tstate != NULL);
255+
/* Signals are always handled by the main interpreter */
256+
PyInterpreterState *interp = _PyRuntime.interpreters.main;
260257

261258
/* Notify ceval.c */
262-
_PyEval_SignalReceived(tstate);
259+
_PyEval_SignalReceived(interp);
263260

264261
/* And then write to the wakeup fd *after* setting all the globals and
265262
doing the _PyEval_SignalReceived. We used to write to the wakeup fd
@@ -299,7 +296,7 @@ trip_signal(int sig_num)
299296
{
300297
/* _PyEval_AddPendingCall() isn't signal-safe, but we
301298
still use it for this exceptional case. */
302-
_PyEval_AddPendingCall(tstate,
299+
_PyEval_AddPendingCall(interp,
303300
report_wakeup_send_error,
304301
(void *)(intptr_t) last_error);
305302
}
@@ -318,7 +315,7 @@ trip_signal(int sig_num)
318315
{
319316
/* _PyEval_AddPendingCall() isn't signal-safe, but we
320317
still use it for this exceptional case. */
321-
_PyEval_AddPendingCall(tstate,
318+
_PyEval_AddPendingCall(interp,
322319
report_wakeup_write_error,
323320
(void *)(intptr_t)errno);
324321
}
@@ -476,7 +473,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
476473
#endif
477474

478475
PyThreadState *tstate = _PyThreadState_GET();
479-
if (!_Py_ThreadCanHandleSignals(tstate)) {
476+
if (!_Py_ThreadCanHandleSignals(tstate->interp)) {
480477
_PyErr_SetString(tstate, PyExc_ValueError,
481478
"signal only works in main thread "
482479
"of the main interpreter");
@@ -704,7 +701,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args, PyObject *kwds)
704701
#endif
705702

706703
PyThreadState *tstate = _PyThreadState_GET();
707-
if (!_Py_ThreadCanHandleSignals(tstate)) {
704+
if (!_Py_ThreadCanHandleSignals(tstate->interp)) {
708705
_PyErr_SetString(tstate, PyExc_ValueError,
709706
"set_wakeup_fd only works in main thread "
710707
"of the main interpreter");
@@ -1681,7 +1678,7 @@ int
16811678
PyErr_CheckSignals(void)
16821679
{
16831680
PyThreadState *tstate = _PyThreadState_GET();
1684-
if (!_Py_ThreadCanHandleSignals(tstate)) {
1681+
if (!_Py_ThreadCanHandleSignals(tstate->interp)) {
16851682
return 0;
16861683
}
16871684

@@ -1787,8 +1784,8 @@ PyOS_FiniInterrupts(void)
17871784
int
17881785
PyOS_InterruptOccurred(void)
17891786
{
1790-
PyThreadState *tstate = _PyThreadState_GET();
1791-
if (!_Py_ThreadCanHandleSignals(tstate)) {
1787+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1788+
if (!_Py_ThreadCanHandleSignals(interp)) {
17921789
return 0;
17931790
}
17941791

@@ -1824,8 +1821,8 @@ _PySignal_AfterFork(void)
18241821
int
18251822
_PyOS_IsMainThread(void)
18261823
{
1827-
PyThreadState *tstate = _PyThreadState_GET();
1828-
return _Py_ThreadCanHandleSignals(tstate);
1824+
PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE();
1825+
return _Py_ThreadCanHandleSignals(interp);
18291826
}
18301827

18311828
#ifdef MS_WINDOWS

0 commit comments

Comments
 (0)