summaryrefslogtreecommitdiffstats
path: root/Modules/signalmodule.c
diff options
context:
space:
mode:
authorJean-Paul Calderone <exarkun@divmod.com>2010-06-19 19:54:48 (GMT)
committerJean-Paul Calderone <exarkun@divmod.com>2010-06-19 19:54:48 (GMT)
commit867c4354609b09b2425b188f212e54fc027be18f (patch)
tree246457fd2c5b2bda15b701a74d38c8b85237fdbb /Modules/signalmodule.c
parent2aa3af4a162e78714b7c4fceecc12fceab60e1bf (diff)
downloadcpython-867c4354609b09b2425b188f212e54fc027be18f.zip
cpython-867c4354609b09b2425b188f212e54fc027be18f.tar.gz
cpython-867c4354609b09b2425b188f212e54fc027be18f.tar.bz2
merge forward from the python 2.x branch
Diffstat (limited to 'Modules/signalmodule.c')
-rw-r--r--Modules/signalmodule.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index f4fd964..026846b 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -22,6 +22,10 @@
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
+#ifdef HAVE_SIGNALFD
+#include <sys/signalfd.h>
+#endif
+
#ifndef SIG_ERR
#define SIG_ERR ((PyOS_sighandler_t)(-1))
@@ -464,6 +468,144 @@ Returns current value of given itimer.");
#endif
+static int
+_iterable_to_mask(PyObject *iterable, sigset_t *mask)
+{
+ static const char* range_format = "signal number %d out of range";
+ char range_buffer[1024];
+ int result = 0;
+
+ PyObject *item, *iterator = NULL;
+
+ sigemptyset(mask);
+
+ iterator = PyObject_GetIter(iterable);
+ if (iterator == NULL) {
+ result = -1;
+ goto error;
+ }
+
+ while ((item = PyIter_Next(iterator))) {
+ int signum = PyInt_AsLong(item);
+ Py_DECREF(item);
+ if (signum == -1 && PyErr_Occurred()) {
+ result = -1;
+ goto error;
+ }
+ if (sigaddset(mask, signum) == -1) {
+ PyOS_snprintf(range_buffer, sizeof(range_buffer), range_format, signum);
+ PyErr_SetString(PyExc_ValueError, range_buffer);
+ result = -1;
+ goto error;
+ }
+ }
+
+error:
+ Py_XDECREF(iterator);
+ return result;
+}
+
+#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
+# define PY_SIGMASK pthread_sigmask
+#elif defined(HAVE_SIGPROCMASK)
+# define PY_SIGMASK sigprocmask
+#endif
+
+#ifdef PY_SIGMASK
+static PyObject *
+signal_sigprocmask(PyObject *self, PyObject *args)
+{
+ static const char* how_format = "value specified for how (%d) invalid";
+ char how_buffer[1024];
+
+ int how, sig;
+ PyObject *signals, *result, *signum;
+ sigset_t mask, previous;
+
+ if (!PyArg_ParseTuple(args, "iO:sigprocmask", &how, &signals)) {
+ return NULL;
+ }
+
+ if (_iterable_to_mask(signals, &mask) == -1) {
+ return NULL;
+ }
+
+ if (PY_SIGMASK(how, &mask, &previous) != 0) {
+ PyOS_snprintf(how_buffer, sizeof(how_buffer), how_format, how);
+ PyErr_SetString(PyExc_ValueError, how_buffer);
+ return NULL;
+ }
+
+ result = PyList_New(0);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ for (sig = 1; sig < NSIG; ++sig) {
+ if (sigismember(&previous, sig) == 1) {
+ /* Handle the case where it is a member by adding the signal to
+ the result list. Ignore the other cases because they mean the
+ signal isn't a member of the mask or the signal was invalid,
+ and an invalid signal must have been our fault in constructing
+ the loop boundaries. */
+ signum = PyInt_FromLong(sig);
+ if (signum == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ if (PyList_Append(result, signum) == -1) {
+ Py_DECREF(signum);
+ Py_DECREF(result);
+ return NULL;
+ }
+ Py_DECREF(signum);
+ }
+ }
+ return result;
+}
+
+PyDoc_STRVAR(sigprocmask_doc,
+"sigprocmask(how, mask) -> old mask\n\
+\n\
+Examine and change blocked signals.");
+#endif
+
+#ifdef HAVE_SIGNALFD
+static PyObject *
+signal_signalfd(PyObject *self, PyObject *args)
+{
+ int result, flags = 0;
+ sigset_t mask;
+
+ int fd;
+ PyObject *signals;
+
+ if (!PyArg_ParseTuple(args, "iO|i:signalfd", &fd, &signals, &flags)) {
+ return NULL;
+ }
+
+ if (_iterable_to_mask(signals, &mask) == -1) {
+ return NULL;
+ }
+
+ result = signalfd(-1, &mask, flags);
+
+ if (result == -1) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+
+ return PyInt_FromLong(result);
+}
+
+PyDoc_STRVAR(signalfd_doc,
+"signalfd(fd, mask, flags)\n\
+\n\
+Create a file descriptor for accepting signals.");
+
+#endif
+
+
/* List of functions defined in the module */
static PyMethodDef signal_methods[] = {
#ifdef HAVE_ALARM
@@ -478,6 +620,14 @@ 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 PY_SIGMASK
+ {"sigprocmask", signal_sigprocmask, METH_VARARGS, sigprocmask_doc},
+/* It's no longer needed, so clean up the namespace. */
+#undef PY_SIGMASK
+#endif
+#ifdef HAVE_SIGNALFD
+ {"signalfd", signal_signalfd, METH_VARARGS, signalfd_doc},
+#endif
#ifdef HAVE_SIGINTERRUPT
{"siginterrupt", signal_siginterrupt, METH_VARARGS, siginterrupt_doc},
#endif
@@ -811,6 +961,36 @@ PyInit_signal(void)
PyDict_SetItemString(d, "ItimerError", ItimerError);
#endif
+#ifdef SIG_BLOCK
+ x = PyLong_FromLong(SIG_BLOCK);
+ PyDict_SetItemString(d, "SIG_BLOCK", x);
+ Py_DECREF(x);
+#endif
+
+#ifdef SIG_UNBLOCK
+ x = PyLong_FromLong(SIG_UNBLOCK);
+ PyDict_SetItemString(d, "SIG_UNBLOCK", x);
+ Py_DECREF(x);
+#endif
+
+#ifdef SIG_SETMASK
+ x = PyLong_FromLong(SIG_SETMASK);
+ PyDict_SetItemString(d, "SIG_SETMASK", x);
+ Py_DECREF(x);
+#endif
+
+#ifdef SFD_CLOEXEC
+ x = PyLong_FromLong(SFD_CLOEXEC);
+ PyDict_SetItemString(d, "SFD_CLOEXEC", x);
+ Py_DECREF(x);
+#endif
+
+#ifdef SFD_NONBLOCK
+ x = PyLong_FromLong(SFD_NONBLOCK);
+ PyDict_SetItemString(d, "SFD_NONBLOCK", x);
+ Py_DECREF(x);
+#endif
+
#ifdef CTRL_C_EVENT
x = PyLong_FromLong(CTRL_C_EVENT);
PyDict_SetItemString(d, "CTRL_C_EVENT", x);