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
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}
\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}
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}
# 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
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"
+
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.
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[] = {
#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 */
};
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\
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;
#! /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.
#
+
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`
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
/* 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