mirror of
https://github.com/python/cpython.git
synced 2025-08-03 08:34:29 +00:00
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.
This commit is contained in:
parent
57826cf9f8
commit
7e251e83d5
4 changed files with 95 additions and 2 deletions
|
@ -124,6 +124,21 @@ The :mod:`signal` module defines the following functions:
|
|||
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
|
||||
|
|
|
@ -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 @@ class WakeupSignalTests(unittest.TestCase):
|
|||
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 @@ def test_main():
|
|||
sys.platform)
|
||||
|
||||
test_support.run_unittest(BasicSignalTests, InterProcessSignalTests,
|
||||
WakeupSignalTests)
|
||||
WakeupSignalTests, SiginterruptTest)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -1186,6 +1186,7 @@ Library
|
|||
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
|
||||
-----------------
|
||||
|
|
|
@ -272,6 +272,36 @@ SIG_DFL -- if the default action for the signal is in effect\n\
|
|||
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 @@ static PyMethodDef signal_methods[] = {
|
|||
{"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},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue