Issue 1089358. Adds the siginterrupt() function, that is just a
wrapper around the system call with the same name. Also added
test cases, doc changes and NEWS entry. Thanks Jason and Ralf
Schmitt.
diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst
index afb3166..7fe7ec1 100644
--- a/Doc/library/signal.rst
+++ b/Doc/library/signal.rst
@@ -124,6 +124,21 @@
exception to be raised.
+
+.. function:: siginterrupt(signalnum, flag)
+
+ Change system call restart behaviour: if *flag* is :const:`False`, system calls
+ will be restarted when interrupted by signal *signalnum*, else system calls will
+ be interrupted. Returns nothing. Availability: Unix, Mac (see the man page
+ :manpage:`siginterrupt(3)` for further information).
+
+ Note that installing a signal handler with :func:`signal` will reset the restart
+ behaviour to interruptible by implicitly calling siginterrupt with a true *flag*
+ value for the given signal.
+
+ .. versionadded:: 2.6
+
+
.. function:: signal(signalnum, handler)
Set the handler for signal *signalnum* to the function *handler*. *handler* can
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index 8cf82f4..332001f 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -1,7 +1,7 @@
import unittest
from test import test_support
import signal
-import os, sys, time
+import os, sys, time, errno
class HandlerBCalled(Exception):
pass
@@ -210,6 +210,50 @@
os.close(self.write)
signal.signal(signal.SIGALRM, self.alrm)
+class SiginterruptTest(unittest.TestCase):
+ signum = signal.SIGUSR1
+ def readpipe_interrupted(self, cb):
+ r, w = os.pipe()
+ ppid = os.getpid()
+ pid = os.fork()
+
+ oldhandler = signal.signal(self.signum, lambda x,y: None)
+ cb()
+ if pid==0:
+ # child code: sleep, kill, sleep. and then exit,
+ # which closes the pipe from which the parent process reads
+ try:
+ time.sleep(0.2)
+ os.kill(ppid, self.signum)
+ time.sleep(0.2)
+ finally:
+ os._exit(0)
+
+ try:
+ os.close(w)
+
+ try:
+ d=os.read(r, 1)
+ return False
+ except OSError, err:
+ if err.errno != errno.EINTR:
+ raise
+ return True
+ finally:
+ signal.signal(self.signum, oldhandler)
+ os.waitpid(pid, 0)
+
+ def test_without_siginterrupt(self):
+ i=self.readpipe_interrupted(lambda: None)
+ self.assertEquals(i, True)
+
+ def test_siginterrupt_on(self):
+ i=self.readpipe_interrupted(lambda: signal.siginterrupt(self.signum, 1))
+ self.assertEquals(i, True)
+
+ def test_siginterrupt_off(self):
+ i=self.readpipe_interrupted(lambda: signal.siginterrupt(self.signum, 0))
+ self.assertEquals(i, False)
def test_main():
if sys.platform[:3] in ('win', 'os2') or sys.platform == 'riscos':
@@ -217,7 +261,7 @@
sys.platform)
test_support.run_unittest(BasicSignalTests, InterProcessSignalTests,
- WakeupSignalTests)
+ WakeupSignalTests, SiginterruptTest)
if __name__ == "__main__":
diff --git a/Misc/NEWS b/Misc/NEWS
index 180d25a..c1172de 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -1186,6 +1186,7 @@
does not claim to support starttls. Adds the SMTP.ehlo_or_helo_if_needed()
method. Patch contributed by Bill Fenner.
+- Patch #1089358: Add signal.siginterrupt, a wrapper around siginterrupt(3).
Extension Modules
-----------------
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index 9dec24f..8acec21 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -272,6 +272,36 @@
None -- if an unknown handler is in effect\n\
anything else -- the callable Python object used as a handler");
+#ifdef HAVE_SIGINTERRUPT
+PyDoc_STRVAR(siginterrupt_doc,
+"siginterrupt(sig, flag) -> None\n\
+change system call restart behaviour: if flag is False, system calls\n\
+will be restarted when interrupted by signal sig, else system calls\n\
+will be interrupted.");
+
+static PyObject *
+signal_siginterrupt(PyObject *self, PyObject *args)
+{
+ int sig_num;
+ int flag;
+
+ if (!PyArg_ParseTuple(args, "ii:siginterrupt", &sig_num, &flag))
+ return NULL;
+ if (sig_num < 1 || sig_num >= NSIG) {
+ PyErr_SetString(PyExc_ValueError,
+ "signal number out of range");
+ return NULL;
+ }
+ if (siginterrupt(sig_num, flag)<0) {
+ PyErr_SetFromErrno(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#endif
static PyObject *
signal_set_wakeup_fd(PyObject *self, PyObject *args)
@@ -325,6 +355,9 @@
{"signal", signal_signal, METH_VARARGS, signal_doc},
{"getsignal", signal_getsignal, METH_VARARGS, getsignal_doc},
{"set_wakeup_fd", signal_set_wakeup_fd, METH_VARARGS, set_wakeup_fd_doc},
+#ifdef HAVE_SIGINTERRUPT
+ {"siginterrupt", signal_siginterrupt, METH_VARARGS, siginterrupt_doc},
+#endif
#ifdef HAVE_PAUSE
{"pause", (PyCFunction)signal_pause,
METH_NOARGS,pause_doc},