This is patch
[ 559250 ] more POSIX signal stuff Adds support (and docs and tests and autoconfery) for posix signal mask handling -- sigpending, sigprocmask and sigsuspend.
This commit is contained in:
parent
e5df1058f1
commit
34f20eac98
|
@ -17,10 +17,6 @@ regardless of the underlying implementation), with the exception of
|
|||
the handler for \constant{SIGCHLD}, which follows the underlying
|
||||
implementation.
|
||||
|
||||
\item
|
||||
There is no way to ``block'' signals temporarily from critical
|
||||
sections (since this is not supported by all \UNIX{} flavors).
|
||||
|
||||
\item
|
||||
Although Python signal handlers are called asynchronously as far as
|
||||
the Python user is concerned, they can only occur between the
|
||||
|
@ -92,6 +88,16 @@ The variables defined in the \module{signal} module are:
|
|||
One more than the number of the highest signal number.
|
||||
\end{datadesc}
|
||||
|
||||
\begin{datadesc}{SIG_BLOCK}
|
||||
\end{datadesc}
|
||||
\begin{datadesc}{SIG_UNBLOCK}
|
||||
\end{datadesc}
|
||||
\begin{datadesc}{SIG_SETMASK}
|
||||
These constants are for use as the first parameter of the
|
||||
\function{sigprocmask} function described below.
|
||||
\end{datadesc}
|
||||
|
||||
|
||||
The \module{signal} module defines the following functions:
|
||||
|
||||
\begin{funcdesc}{alarm}{time}
|
||||
|
@ -144,6 +150,46 @@ The \module{signal} module defines the following functions:
|
|||
\obindex{frame}
|
||||
\end{funcdesc}
|
||||
|
||||
The following functions are supported if your platform does. Most
|
||||
modern \UNIX-alikes now do.
|
||||
|
||||
\begin{funcdesc}{sigpending}{}
|
||||
Return the set of pending signals, i.e. a list containing the
|
||||
numbers of those signals that have been raised while blocked.
|
||||
\versionadded{2.3}
|
||||
\end{funcdesc}
|
||||
|
||||
\begin{funcdesc}{sigprocmask}{how, sigset}
|
||||
Change the list of currently blocked signals. The parameter
|
||||
\var{how} should be one of \constant{SIG_BLOCK},
|
||||
\constant{SIG_UNBLOCK} or \constant{SIG_SETMASK} and \var{sigset}
|
||||
should be a sequence of signal numbers. The behaviour of the call
|
||||
depends on the value of \var{how}:
|
||||
|
||||
\begin{tableii}{l|l}{textrm}{Value of \var{how}}{Behaviour of call}
|
||||
\lineii{\constant{SIG_BLOCK}}
|
||||
{The set of blocked signals is the union of the current set
|
||||
and \var{sigset}.}
|
||||
\lineii{\constant{SIG_UNBLOCK}}
|
||||
{The signals in \var{sigset} are removed from the current
|
||||
set of blocked signals. It is legal to attempt to unblock
|
||||
a signal which is not blocked.}
|
||||
\lineii{\constant{SIG_SETMASK}}
|
||||
{The set of blocked signals is set to the \var{sigset}.}
|
||||
\end{tableii}
|
||||
|
||||
A list contating the numbers of the previously blocked signals is
|
||||
returned.
|
||||
\versionadded{2.3}
|
||||
\end{funcdesc}
|
||||
|
||||
\begin{funcdesc}{sigsuspend}{sigset}
|
||||
Temporarily replace the signal mask with \var{sigset} (which should
|
||||
be a sequnce of signal numbers) and suspend the process until a
|
||||
signal is received.
|
||||
\versionadded{2.3}
|
||||
\end{funcdesc}
|
||||
|
||||
\subsection{Example}
|
||||
\nodename{Signal Example}
|
||||
|
||||
|
|
|
@ -532,6 +532,12 @@ contents, and the \code{*=} assignment operator to repeat an array.
|
|||
functions: \function{get_history_item()},
|
||||
\function{get_current_history_length()}, and \function{redisplay()}.
|
||||
|
||||
\item Support for more advanced POSIX signal handling -- specifically
|
||||
the functions \function{sigpending}, \function{sigprocmask} and
|
||||
\function{sigsupend}, and depending on platform support -- was added
|
||||
to the \module{signal} module. These functions make some previously
|
||||
unavoidable race conditions avoidable.
|
||||
|
||||
\end{itemize}
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
# Test the signal module
|
||||
from test_support import verbose, TestSkipped
|
||||
from test_support import verbose, TestSkipped, TestFailed
|
||||
import signal
|
||||
import os
|
||||
import sys
|
||||
import os, sys, time
|
||||
|
||||
if sys.platform[:3] in ('win', 'os2') or sys.platform=='riscos':
|
||||
raise TestSkipped, "Can't test signal on %s" % sys.platform
|
||||
|
@ -64,3 +63,66 @@ try:
|
|||
except KeyboardInterrupt:
|
||||
if verbose:
|
||||
print "KeyboardInterrupt (assume the alarm() went off)"
|
||||
|
||||
|
||||
if hasattr(signal, "sigprocmask"):
|
||||
class HupDelivered(Exception):
|
||||
pass
|
||||
def hup(signum, frame):
|
||||
raise HupDelivered
|
||||
def hup2(signum, frame):
|
||||
signal.signal(signal.SIGHUP, hup)
|
||||
return
|
||||
signal.signal(signal.SIGHUP, hup)
|
||||
|
||||
if verbose:
|
||||
print "blocking SIGHUP"
|
||||
|
||||
defaultmask = signal.sigprocmask(signal.SIG_BLOCK, [signal.SIGHUP])
|
||||
|
||||
if verbose:
|
||||
print "sending SIGHUP"
|
||||
|
||||
try:
|
||||
os.kill(pid, signal.SIGHUP)
|
||||
except HupDelivered:
|
||||
raise TestFailed, "HUP not blocked"
|
||||
|
||||
if signal.SIGHUP not in signal.sigpending():
|
||||
raise TestFailed, "HUP not pending"
|
||||
|
||||
if verbose:
|
||||
print "unblocking SIGHUP"
|
||||
|
||||
try:
|
||||
signal.sigprocmask(signal.SIG_UNBLOCK, [signal.SIGHUP])
|
||||
except HupDelivered:
|
||||
pass
|
||||
else:
|
||||
raise TestFailed, "HUP not delivered"
|
||||
|
||||
if verbose:
|
||||
print "testing sigsuspend"
|
||||
|
||||
signal.sigprocmask(signal.SIG_BLOCK, [signal.SIGHUP])
|
||||
signal.signal(signal.SIGHUP, hup2)
|
||||
|
||||
if not os.fork():
|
||||
time.sleep(2)
|
||||
os.kill(pid, signal.SIGHUP)
|
||||
time.sleep(2)
|
||||
os.kill(pid, signal.SIGHUP)
|
||||
os._exit(0)
|
||||
else:
|
||||
try:
|
||||
signal.sigsuspend(defaultmask)
|
||||
except:
|
||||
raise TestFailed, "sigsuspend erroneously raised"
|
||||
|
||||
try:
|
||||
signal.sigsuspend(defaultmask)
|
||||
except HupDelivered:
|
||||
pass
|
||||
else:
|
||||
raise TestFailed, "sigsupsend didn't raise"
|
||||
|
||||
|
|
|
@ -106,6 +106,9 @@ Extension modules
|
|||
of sizeof(int)!=sizeof(long)!=sizeof(void*) is delayed until dl.open
|
||||
is called.
|
||||
|
||||
- signal.sigpending, signal.sigprocmask and signal.sigsuspend have
|
||||
been added where available.
|
||||
|
||||
Library
|
||||
|
||||
- added degree/radian conversion functions to the math module.
|
||||
|
|
|
@ -270,6 +270,153 @@ None -- if an unknown handler is in effect\n\
|
|||
anything else -- the callable Python object used as a handler\n\
|
||||
";
|
||||
|
||||
#ifdef HAVE_SIGPROCMASK /* we assume that having SIGPROCMASK is enough
|
||||
to guarantee full POSIX signal handling */
|
||||
/* returns 0 for success, <0 for failure (with exception set) */
|
||||
static int
|
||||
_signal_list_to_sigset(PyObject* seq, sigset_t* set, char* mesg)
|
||||
{
|
||||
int i, len, val;
|
||||
|
||||
seq = PySequence_Fast(seq, mesg);
|
||||
if (!seq)
|
||||
return -1;
|
||||
|
||||
len = PySequence_Fast_GET_SIZE(seq);
|
||||
|
||||
sigemptyset(set);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
val = PyInt_AsLong(PySequence_Fast_GET_ITEM(seq, i));
|
||||
if (val == -1 && PyErr_Occurred()) {
|
||||
Py_DECREF(seq);
|
||||
return -1;
|
||||
}
|
||||
if (sigaddset(set, val) < 0) {
|
||||
Py_DECREF(seq);
|
||||
PyErr_SetFromErrno(PyExc_ValueError);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(seq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
_signal_sigset_to_list(sigset_t* set)
|
||||
{
|
||||
PyObject* ret;
|
||||
PyObject* ob;
|
||||
int i;
|
||||
|
||||
ret = PyList_New(0);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(set, i)) {
|
||||
ob = PyInt_FromLong(i);
|
||||
if (!ob) {
|
||||
Py_DECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
PyList_Append(ret, ob);
|
||||
Py_DECREF(ob);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
signal_sigprocmask(PyObject* self, PyObject* args)
|
||||
{
|
||||
int how;
|
||||
sigset_t newset, oldset;
|
||||
PyObject* seq;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iO", &how, &seq))
|
||||
return NULL;
|
||||
|
||||
if (_signal_list_to_sigset(seq, &newset,
|
||||
"sigprocmask requires a sequence") < 0)
|
||||
return NULL;
|
||||
|
||||
if (sigprocmask(how, &newset, &oldset) < 0) {
|
||||
return PyErr_SetFromErrno(PyExc_ValueError);
|
||||
}
|
||||
|
||||
if (PyErr_CheckSignals())
|
||||
return NULL;
|
||||
|
||||
return _signal_sigset_to_list(&oldset);
|
||||
}
|
||||
|
||||
static char sigprocmask_doc[] =
|
||||
"sigprocmask(how, sigset) -> sigset\n\
|
||||
\n\
|
||||
Change the list of currently blocked signals. The parameter how should be\n\
|
||||
one of SIG_BLOCK, SIG_UNBLOCK or SIG_SETMASK and sigset should be a\n\
|
||||
sequence of signal numbers. The behaviour of the call depends on the value\n\
|
||||
of how:\n\
|
||||
\n\
|
||||
SIG_BLOCK\n\
|
||||
The set of blocked signals is the union of the current set and the\n\
|
||||
sigset argument.\n\
|
||||
SIG_UNBLOCK\n\
|
||||
The signals in sigset are removed from the current set of blocked\n\
|
||||
signals. It is legal to attempt to unblock a signal which is not\n\
|
||||
blocked.\n\
|
||||
SIG_SETMASK\n\
|
||||
The set of blocked signals is set to the argument set.\n\
|
||||
\n\
|
||||
A list contating the numbers of the previously blocked signals is returned.";
|
||||
|
||||
static PyObject*
|
||||
signal_sigpending(PyObject* self)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (sigpending(&set) < 0) {
|
||||
return PyErr_SetFromErrno(PyExc_ValueError);
|
||||
}
|
||||
|
||||
return _signal_sigset_to_list(&set);
|
||||
}
|
||||
|
||||
static char sigpending_doc[] =
|
||||
"sigpending() -> sigset\n\
|
||||
\n\
|
||||
Return the set of pending signals, i.e. a list containing the numbers of\n\
|
||||
those signals that have been raised while blocked.";
|
||||
|
||||
static PyObject*
|
||||
signal_sigsuspend(PyObject* self, PyObject* arg)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (_signal_list_to_sigset(arg, &set,
|
||||
"sigsuspend requires a sequence") < 0)
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
sigsuspend(&set);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (PyErr_CheckSignals())
|
||||
return NULL;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static char sigsuspend_doc[] =
|
||||
"sigsuspend(sigset) -> None\n\
|
||||
\n\
|
||||
Temporarily replace the signal mask with sigset (which should be a sequence\n\
|
||||
of signal numbers) and suspend the process until a signal is received.";
|
||||
#endif
|
||||
|
||||
/* List of functions defined in the module */
|
||||
static PyMethodDef signal_methods[] = {
|
||||
|
@ -284,6 +431,14 @@ static PyMethodDef signal_methods[] = {
|
|||
#endif
|
||||
{"default_int_handler", signal_default_int_handler,
|
||||
METH_VARARGS, default_int_handler_doc},
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
{"sigprocmask", (PyCFunction)signal_sigprocmask,
|
||||
METH_VARARGS, sigprocmask_doc},
|
||||
{"sigpending", (PyCFunction)signal_sigpending,
|
||||
METH_NOARGS, sigpending_doc},
|
||||
{"sigsuspend", (PyCFunction)signal_sigsuspend,
|
||||
METH_O, sigsuspend_doc},
|
||||
#endif
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
@ -299,6 +454,10 @@ getsignal() -- get the signal action for a given signal\n\
|
|||
pause() -- wait until a signal arrives [Unix only]\n\
|
||||
default_int_handler() -- default SIGINT handler\n\
|
||||
\n\
|
||||
sigpending() |\n\
|
||||
sigprocmask() |-- posix signal mask handling [Unix only]\n\
|
||||
sigsuspend() |\n\
|
||||
\n\
|
||||
Constants:\n\
|
||||
\n\
|
||||
SIG_DFL -- used to refer to the system default handler\n\
|
||||
|
@ -547,6 +706,18 @@ initsignal(void)
|
|||
PyDict_SetItemString(d, "SIGINFO", x);
|
||||
Py_XDECREF(x);
|
||||
#endif
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
x = PyInt_FromLong(SIG_BLOCK);
|
||||
PyDict_SetItemString(d, "SIG_BLOCK", x);
|
||||
Py_XDECREF(x);
|
||||
x = PyInt_FromLong(SIG_UNBLOCK);
|
||||
PyDict_SetItemString(d, "SIG_UNBLOCK", x);
|
||||
Py_XDECREF(x);
|
||||
x = PyInt_FromLong(SIG_SETMASK);
|
||||
PyDict_SetItemString(d, "SIG_SETMASK", x);
|
||||
Py_XDECREF(x);
|
||||
#endif
|
||||
|
||||
if (!PyErr_Occurred())
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#! /bin/sh
|
||||
# From configure.in Revision: 1.316 .
|
||||
# From configure.in Revision: 1.317 .
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.53.
|
||||
#
|
||||
|
@ -11276,6 +11276,7 @@ echo "${ECHO_T}MACHDEP_OBJS" >&6
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for ac_func in alarm chown chroot clock confstr ctermid ctermid_r execv \
|
||||
|
@ -11286,8 +11287,8 @@ for ac_func in alarm chown chroot clock confstr ctermid ctermid_r execv \
|
|||
putenv readlink \
|
||||
select setegid seteuid setgid setgroups \
|
||||
setlocale setregid setreuid setsid setpgid setuid setvbuf snprintf \
|
||||
sigaction siginterrupt sigrelse strftime strptime symlink sysconf \
|
||||
tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
|
||||
sigaction siginterrupt sigprocmask sigrelse strftime strptime symlink \
|
||||
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
|
||||
truncate uname unsetenv waitpid _getpty getpriority
|
||||
do
|
||||
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
|
|
|
@ -1593,8 +1593,8 @@ AC_CHECK_FUNCS(alarm chown chroot clock confstr ctermid ctermid_r execv \
|
|||
putenv readlink \
|
||||
select setegid seteuid setgid setgroups \
|
||||
setlocale setregid setreuid setsid setpgid setuid setvbuf snprintf \
|
||||
sigaction siginterrupt sigrelse strftime strptime symlink sysconf \
|
||||
tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
|
||||
sigaction siginterrupt sigprocmask sigrelse strftime strptime symlink \
|
||||
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
|
||||
truncate uname unsetenv waitpid _getpty getpriority)
|
||||
|
||||
# check for openpty and forkpty
|
||||
|
|
|
@ -383,6 +383,9 @@
|
|||
/* Define to 1 if you have the <signal.h> header file. */
|
||||
#undef HAVE_SIGNAL_H
|
||||
|
||||
/* Define to 1 if you have the `sigprocmask' function. */
|
||||
#undef HAVE_SIGPROCMASK
|
||||
|
||||
/* Define to 1 if you have the `sigrelse' function. */
|
||||
#undef HAVE_SIGRELSE
|
||||
|
||||
|
|
Loading…
Reference in New Issue