[Python-checkins] bpo-35724: Explicitly require the main interpreter for signal-handling. (GH-11530)

Eric Snow webhook-mailer at python.org
Sat Feb 23 17:40:50 EST 2019


https://github.com/python/cpython/commit/64d6cc826dacebc2493b1bb5e8cb97828eb76f81
commit: 64d6cc826dacebc2493b1bb5e8cb97828eb76f81
branch: master
author: Eric Snow <ericsnowcurrently at gmail.com>
committer: GitHub <noreply at github.com>
date: 2019-02-23T15:40:43-07:00
summary:

bpo-35724: Explicitly require the main interpreter for signal-handling. (GH-11530)

Ensure that the main interpreter is active (in the main thread) for signal-handling operations. This is increasingly relevant as people use subinterpreters more.

https://bugs.python.org/issue35724

files:
A Misc/NEWS.d/next/Core and Builtins/2019-01-11-14-46-08.bpo-35724.Wv79MG.rst
M Include/cpython/pyerrors.h
M Modules/signalmodule.c
M Python/ceval.c

diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h
index 0b43d7528b97..de6548dc9c0b 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 000000000000..d2d74e56cb21
--- /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 9d49cbd14400..f29720bcaf36 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);
@@ -1606,6 +1615,18 @@ finisignal(void)
 /* Declared in pyerrors.h */
 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;
@@ -1613,9 +1634,6 @@ PyErr_CheckSignals(void)
     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 03456f6d2ab4..439f4f156e8b 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;
     }



More information about the Python-checkins mailing list