summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_faulthandler.py26
-rw-r--r--Lib/test/test_signal.py65
-rw-r--r--Modules/_testcapimodule.c21
-rw-r--r--Modules/faulthandler.c26
4 files changed, 85 insertions, 53 deletions
diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py
index b0fc279..f514f57 100644
--- a/Lib/test/test_faulthandler.py
+++ b/Lib/test/test_faulthandler.py
@@ -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):
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index 92747cf..de3b40f 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -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:
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 05a27d6..ebbf88f 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -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")},
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index 6a145dc..97963ef 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -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)