summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/cpython/pyerrors.h1
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2019-01-11-14-46-08.bpo-35724.Wv79MG.rst2
-rw-r--r--Modules/signalmodule.c36
-rw-r--r--Python/ceval.c9
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;
}