]> granicus.if.org Git - python/commitdiff
Issue #22018: Add _testcapi.raise_signal()
authorVictor Stinner <victor.stinner@gmail.com>
Mon, 21 Jul 2014 10:30:22 +0000 (12:30 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Mon, 21 Jul 2014 10:30:22 +0000 (12:30 +0200)
- Use _testcapi.raise_signal() in test_signal
- close also os.pipe() file descriptors in some test_signal tests where they
  were not closed properly
- Remove faulthandler._sigill() and faulthandler._sigbus(): reuse
  _testcapi.raise_signal() in test_faulthandler

Lib/test/test_faulthandler.py
Lib/test/test_signal.py
Modules/_testcapimodule.c
Modules/faulthandler.c

index b0fc279706d95c96502a94e79ea80b161c853eae..f514f57819f540f8a7c01b998dd7a71fae8a331d 100644 (file)
@@ -16,6 +16,10 @@ try:
     HAVE_THREADS = True
 except ImportError:
     HAVE_THREADS = False
+try:
+    import _testcapi
+except ImportError:
+    _testcapi = None
 
 TIMEOUT = 0.5
 
@@ -133,26 +137,32 @@ faulthandler._sigfpe()
             3,
             'Floating point exception')
 
-    @unittest.skipIf(not hasattr(faulthandler, '_sigbus'),
-                     "need faulthandler._sigbus()")
+    @unittest.skipIf(_testcapi is None, 'need _testcapi')
+    @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
     def test_sigbus(self):
         self.check_fatal_error("""
+import _testcapi
 import faulthandler
+import signal
+
 faulthandler.enable()
-faulthandler._sigbus()
+_testcapi.raise_signal(signal.SIGBUS)
 """.strip(),
-            3,
+            6,
             'Bus error')
 
-    @unittest.skipIf(not hasattr(faulthandler, '_sigill'),
-                     "need faulthandler._sigill()")
+    @unittest.skipIf(_testcapi is None, 'need _testcapi')
+    @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
     def test_sigill(self):
         self.check_fatal_error("""
+import _testcapi
 import faulthandler
+import signal
+
 faulthandler.enable()
-faulthandler._sigill()
+_testcapi.raise_signal(signal.SIGILL)
 """.strip(),
-            3,
+            6,
             'Illegal instruction')
 
     def test_fatal_error(self):
index 92747cf109c42fc40aa28c4ec705b1390d854c9a..de3b40f746a1510adfccd76dddfbdb582480a3f4 100644 (file)
@@ -15,6 +15,10 @@ try:
     import threading
 except ImportError:
     threading = None
+try:
+    import _testcapi
+except ImportError:
+    _testcapi = None
 
 
 class HandlerBCalled(Exception):
@@ -250,12 +254,27 @@ class WakeupFDTests(unittest.TestCase):
         fd = support.make_bad_fd()
         self.assertRaises(ValueError, signal.set_wakeup_fd, fd)
 
+    def test_set_wakeup_fd_result(self):
+        r1, w1 = os.pipe()
+        os.close(r1)
+        self.addCleanup(os.close, w1)
+        r2, w2 = os.pipe()
+        os.close(r2)
+        self.addCleanup(os.close, w2)
+
+        signal.set_wakeup_fd(w1)
+        self.assertIs(signal.set_wakeup_fd(w2), w1)
+        self.assertIs(signal.set_wakeup_fd(-1), w2)
+        self.assertIs(signal.set_wakeup_fd(-1), -1)
+
 
 @unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
 class WakeupSignalTests(unittest.TestCase):
+    @unittest.skipIf(_testcapi is None, 'need _testcapi')
     def check_wakeup(self, test_body, *signals, ordered=True):
         # use a subprocess to have only one thread
         code = """if 1:
+        import _testcapi
         import fcntl
         import os
         import signal
@@ -294,17 +313,18 @@ class WakeupSignalTests(unittest.TestCase):
 
         assert_python_ok('-c', code)
 
+    @unittest.skipIf(_testcapi is None, 'need _testcapi')
     def test_wakeup_write_error(self):
         # Issue #16105: write() errors in the C signal handler should not
         # pass silently.
         # Use a subprocess to have only one thread.
         code = """if 1:
+        import _testcapi
         import errno
         import fcntl
         import os
         import signal
         import sys
-        import time
         from test.support import captured_stderr
 
         def handler(signum, frame):
@@ -319,8 +339,7 @@ class WakeupSignalTests(unittest.TestCase):
         signal.set_wakeup_fd(r)
         try:
             with captured_stderr() as err:
-                signal.alarm(1)
-                time.sleep(5.0)
+                _testcapi.raise_signal(signal.SIGALRM)
         except ZeroDivisionError:
             # An ignored exception should have been printed out on stderr
             err = err.getvalue()
@@ -331,6 +350,9 @@ class WakeupSignalTests(unittest.TestCase):
                 raise AssertionError(err)
         else:
             raise AssertionError("ZeroDivisionError not raised")
+
+        os.close(r)
+        os.close(w)
         """
         r, w = os.pipe()
         try:
@@ -394,9 +416,10 @@ class WakeupSignalTests(unittest.TestCase):
 
     def test_signum(self):
         self.check_wakeup("""def test():
+            import _testcapi
             signal.signal(signal.SIGUSR1, handler)
-            os.kill(os.getpid(), signal.SIGUSR1)
-            os.kill(os.getpid(), signal.SIGALRM)
+            _testcapi.raise_signal(signal.SIGUSR1)
+            _testcapi.raise_signal(signal.SIGALRM)
         """, signal.SIGUSR1, signal.SIGALRM)
 
     @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
@@ -410,8 +433,8 @@ class WakeupSignalTests(unittest.TestCase):
             signal.signal(signum2, handler)
 
             signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2))
-            os.kill(os.getpid(), signum1)
-            os.kill(os.getpid(), signum2)
+            _testcapi.raise_signal(signum1)
+            _testcapi.raise_signal(signum2)
             # Unblocking the 2 signals calls the C signal handler twice
             signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2))
         """,  signal.SIGUSR1, signal.SIGUSR2, ordered=False)
@@ -447,18 +470,22 @@ class SiginterruptTest(unittest.TestCase):
             sys.stdout.flush()
 
             # run the test twice
-            for loop in range(2):
-                # send a SIGALRM in a second (during the read)
-                signal.alarm(1)
-                try:
-                    # blocking call: read from a pipe without data
-                    os.read(r, 1)
-                except OSError as err:
-                    if err.errno != errno.EINTR:
-                        raise
-                else:
-                    sys.exit(2)
-            sys.exit(3)
+            try:
+                for loop in range(2):
+                    # send a SIGALRM in a second (during the read)
+                    signal.alarm(1)
+                    try:
+                        # blocking call: read from a pipe without data
+                        os.read(r, 1)
+                    except OSError as err:
+                        if err.errno != errno.EINTR:
+                            raise
+                    else:
+                        sys.exit(2)
+                sys.exit(3)
+            finally:
+                os.close(r)
+                os.close(w)
         """ % (interrupt,)
         with spawn_python('-c', code) as process:
             try:
index 05a27d61f6765b399db4d431a204c8ec8a2a5719..ebbf88f71a48ab1c076b11cf2b7af68704fc0b17 100644 (file)
@@ -11,6 +11,7 @@
 #include <float.h>
 #include "structmember.h"
 #include "datetime.h"
+#include <signal.h>
 
 #ifdef WITH_THREAD
 #include "pythread.h"
@@ -3063,6 +3064,24 @@ exit:
 }
 #endif   /* WITH_THREAD */
 
+static PyObject*
+test_raise_signal(PyObject* self, PyObject *args)
+{
+    int signum, err;
+
+    if (PyArg_ParseTuple(args, "i:raise_signal", &signum) < 0)
+        return NULL;
+
+    err = raise(signum);
+    if (err)
+        return PyErr_SetFromErrno(PyExc_OSError);
+
+    if (PyErr_CheckSignals() < 0)
+        return NULL;
+
+    Py_RETURN_NONE;
+}
+
 
 static PyMethodDef TestMethods[] = {
     {"raise_exception",         raise_exception,                 METH_VARARGS},
@@ -3198,6 +3217,8 @@ static PyMethodDef TestMethods[] = {
     {"docstring_with_signature_with_defaults",
         (PyCFunction)test_with_docstring, METH_NOARGS,
         docstring_with_signature_with_defaults},
+    {"raise_signal",
+     (PyCFunction)test_raise_signal, METH_VARARGS},
 #ifdef WITH_THREAD
     {"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_O,
      PyDoc_STR("set_error_class(error_class) -> None")},
index 6a145dc5f04a79656ef013427bfbaa3ad986abfe..97963efcdf48743b9fe31faa345c8a6cd7f0bdc2 100644 (file)
@@ -874,24 +874,6 @@ faulthandler_sigabrt(PyObject *self, PyObject *args)
     Py_RETURN_NONE;
 }
 
-#ifdef SIGBUS
-static PyObject *
-faulthandler_sigbus(PyObject *self, PyObject *args)
-{
-    raise(SIGBUS);
-    Py_RETURN_NONE;
-}
-#endif
-
-#ifdef SIGILL
-static PyObject *
-faulthandler_sigill(PyObject *self, PyObject *args)
-{
-    raise(SIGILL);
-    Py_RETURN_NONE;
-}
-#endif
-
 static PyObject *
 faulthandler_fatal_error_py(PyObject *self, PyObject *args)
 {
@@ -1012,14 +994,6 @@ static PyMethodDef module_methods[] = {
      PyDoc_STR("_sigabrt(): raise a SIGABRT signal")},
     {"_sigfpe", (PyCFunction)faulthandler_sigfpe, METH_NOARGS,
      PyDoc_STR("_sigfpe(): raise a SIGFPE signal")},
-#ifdef SIGBUS
-    {"_sigbus", (PyCFunction)faulthandler_sigbus, METH_NOARGS,
-     PyDoc_STR("_sigbus(): raise a SIGBUS signal")},
-#endif
-#ifdef SIGILL
-    {"_sigill", (PyCFunction)faulthandler_sigill, METH_NOARGS,
-     PyDoc_STR("_sigill(): raise a SIGILL signal")},
-#endif
     {"_fatal_error", faulthandler_fatal_error_py, METH_VARARGS,
      PyDoc_STR("_fatal_error(message): call Py_FatalError(message)")},
 #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)