diff options
-rw-r--r-- | Include/cpython/pyerrors.h | 1 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2019-01-11-14-46-08.bpo-35724.Wv79MG.rst | 2 | ||||
-rw-r--r-- | Modules/signalmodule.c | 36 | ||||
-rw-r--r-- | Python/ceval.c | 9 |
4 files changed, 39 insertions, 9 deletions
diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 0b43d75..de6548d 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -133,6 +133,7 @@ PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause( /* In signalmodule.c */ int PySignal_SetWakeupFd(int fd); +PyAPI_FUNC(int) _PyErr_CheckSignals(void); /* Support for adding program text to SyntaxErrors */ diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-01-11-14-46-08.bpo-35724.Wv79MG.rst b/Misc/NEWS.d/next/Core and Builtins/2019-01-11-14-46-08.bpo-35724.Wv79MG.rst new file mode 100644 index 0000000..d2d74e5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-01-11-14-46-08.bpo-35724.Wv79MG.rst @@ -0,0 +1,2 @@ +Signal-handling is now guaranteed to happen relative to the main +interpreter. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 9d49cbd..f29720b 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -99,6 +99,7 @@ class sigset_t_converter(CConverter): #include "pythread.h" static unsigned long main_thread; static pid_t main_pid; +static PyInterpreterState *main_interp; static volatile struct { _Py_atomic_int tripped; @@ -185,6 +186,13 @@ itimer_retval(struct itimerval *iv) } #endif +static int +is_main(void) +{ + return PyThread_get_thread_ident() == main_thread && + _PyInterpreterState_Get() == main_interp; +} + static PyObject * signal_default_int_handler(PyObject *self, PyObject *args) { @@ -464,7 +472,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler) return NULL; } #endif - if (PyThread_get_thread_ident() != main_thread) { + if (!is_main()) { PyErr_SetString(PyExc_ValueError, "signal only works in main thread"); return NULL; @@ -486,7 +494,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler) else func = signal_handler; /* Check for pending signals before changing signal handler */ - if (PyErr_CheckSignals()) { + if (_PyErr_CheckSignals()) { return NULL; } if (PyOS_setsig(signalnum, func) == SIG_ERR) { @@ -681,7 +689,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args, PyObject *kwds) return NULL; #endif - if (PyThread_get_thread_ident() != main_thread) { + if (!is_main()) { PyErr_SetString(PyExc_ValueError, "set_wakeup_fd only works in main thread"); return NULL; @@ -1314,6 +1322,7 @@ PyInit__signal(void) main_thread = PyThread_get_thread_ident(); main_pid = getpid(); + main_interp = _PyInterpreterState_Get(); /* Create the module and add the functions */ m = PyModule_Create(&signalmodule); @@ -1607,15 +1616,24 @@ finisignal(void) int PyErr_CheckSignals(void) { + if (!is_main()) { + return 0; + } + + return _PyErr_CheckSignals(); +} + + +/* Declared in cpython/pyerrors.h */ +int +_PyErr_CheckSignals(void) +{ int i; PyObject *f; if (!_Py_atomic_load(&is_tripped)) return 0; - if (PyThread_get_thread_ident() != main_thread) - return 0; - /* * The is_tripped variable is meant to speed up the calls to * PyErr_CheckSignals (both directly or via pending calls) when no @@ -1687,8 +1705,9 @@ int PyOS_InterruptOccurred(void) { if (_Py_atomic_load_relaxed(&Handlers[SIGINT].tripped)) { - if (PyThread_get_thread_ident() != main_thread) + if (!is_main()) { return 0; + } _Py_atomic_store_relaxed(&Handlers[SIGINT].tripped, 0); return 1; } @@ -1716,12 +1735,13 @@ _PySignal_AfterFork(void) _clear_pending_signals(); main_thread = PyThread_get_thread_ident(); main_pid = getpid(); + main_interp = _PyInterpreterState_Get(); } int _PyOS_IsMainThread(void) { - return PyThread_get_thread_ident() == main_thread; + return is_main(); } #ifdef MS_WINDOWS diff --git a/Python/ceval.c b/Python/ceval.c index 03456f6..439f4f1 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -379,9 +379,16 @@ handle_signals(void) { return 0; } + /* + * Ensure that the thread isn't currently running some other + * interpreter. + */ + if (_PyInterpreterState_GET_UNSAFE() != _PyRuntime.interpreters.main) { + return 0; + } UNSIGNAL_PENDING_SIGNALS(); - if (PyErr_CheckSignals() < 0) { + if (_PyErr_CheckSignals() < 0) { SIGNAL_PENDING_SIGNALS(); /* We're not done yet */ return -1; } |