summaryrefslogtreecommitdiffstats
path: root/Modules/signalmodule.c
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@haypocalc.com>2011-04-30 13:21:58 (GMT)
committerVictor Stinner <victor.stinner@haypocalc.com>2011-04-30 13:21:58 (GMT)
commita92933596156337cc004027e41073db6d68616b9 (patch)
tree581f92c46d9bb5302e5dc49007b2998a58ac19e8 /Modules/signalmodule.c
parentd5c355ccc70d011ef2010537838d9a82e24b2b80 (diff)
downloadcpython-a92933596156337cc004027e41073db6d68616b9.zip
cpython-a92933596156337cc004027e41073db6d68616b9.tar.gz
cpython-a92933596156337cc004027e41073db6d68616b9.tar.bz2
Issue #8407, issue #11859: Add signal.pthread_sigmask() function to fetch
and/or change the signal mask of the calling thread. Fix also tests of test_io using threads and an alarm: use pthread_sigmask() to ensure that the SIGALRM signal is received by the main thread. Original patch written by Jean-Paul Calderone.
Diffstat (limited to 'Modules/signalmodule.c')
-rw-r--r--Modules/signalmodule.c139
1 files changed, 138 insertions, 1 deletions
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index 00a83b4..305261c 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -22,6 +22,14 @@
#include <sys/time.h>
#endif
+#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
+# define PYPTHREAD_SIGMASK
+#endif
+
+#if defined(PYPTHREAD_SIGMASK) && defined(HAVE_PTHREAD_H)
+# include <pthread.h>
+#endif
+
#ifndef SIG_ERR
#define SIG_ERR ((PyOS_sighandler_t)(-1))
#endif
@@ -495,6 +503,110 @@ PyDoc_STRVAR(getitimer_doc,
Returns current value of given itimer.");
#endif
+#ifdef PYPTHREAD_SIGMASK
+/* Convert an iterable to a sigset.
+ Return 0 on success, return -1 and raise an exception on error. */
+
+static int
+iterable_to_sigset(PyObject *iterable, sigset_t *mask)
+{
+ int result = -1;
+ PyObject *iterator, *item;
+ long signum;
+ int err;
+
+ sigemptyset(mask);
+
+ iterator = PyObject_GetIter(iterable);
+ if (iterator == NULL)
+ goto error;
+
+ while (1)
+ {
+ item = PyIter_Next(iterator);
+ if (item == NULL) {
+ if (PyErr_Occurred())
+ goto error;
+ else
+ break;
+ }
+
+ signum = PyLong_AsLong(item);
+ Py_DECREF(item);
+ if (signum == -1 && PyErr_Occurred())
+ goto error;
+ if (0 < signum && signum < NSIG)
+ err = sigaddset(mask, (int)signum);
+ else
+ err = 1;
+ if (err) {
+ PyErr_Format(PyExc_ValueError,
+ "signal number %ld out of range", signum);
+ goto error;
+ }
+ }
+ result = 0;
+
+error:
+ Py_XDECREF(iterator);
+ return result;
+}
+
+static PyObject *
+signal_pthread_sigmask(PyObject *self, PyObject *args)
+{
+ int how, sig;
+ PyObject *signals, *result, *signum;
+ sigset_t mask, previous;
+ int err;
+
+ if (!PyArg_ParseTuple(args, "iO:pthread_sigmask", &how, &signals))
+ return NULL;
+
+ if (iterable_to_sigset(signals, &mask))
+ return NULL;
+
+ err = pthread_sigmask(how, &mask, &previous);
+ if (err != 0) {
+ errno = err;
+ PyErr_SetFromErrno(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ result = PyList_New(0);
+ if (result == NULL)
+ return NULL;
+
+ for (sig = 1; sig < NSIG; sig++) {
+ if (sigismember(&previous, sig) != 1)
+ continue;
+
+ /* 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 = PyLong_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(signal_pthread_sigmask_doc,
+"pthread_sigmask(how, mask) -> old mask\n\
+\n\
+Fetch and/or change the signal mask of the calling thread.");
+#endif /* #ifdef PYPTHREAD_SIGMASK */
+
/* List of functions defined in the module */
static PyMethodDef signal_methods[] = {
@@ -515,10 +627,14 @@ static PyMethodDef signal_methods[] = {
#endif
#ifdef HAVE_PAUSE
{"pause", (PyCFunction)signal_pause,
- METH_NOARGS,pause_doc},
+ METH_NOARGS, pause_doc},
#endif
{"default_int_handler", signal_default_int_handler,
METH_VARARGS, default_int_handler_doc},
+#ifdef PYPTHREAD_SIGMASK
+ {"pthread_sigmask", (PyCFunction)signal_pthread_sigmask,
+ METH_VARARGS, signal_pthread_sigmask_doc},
+#endif
{NULL, NULL} /* sentinel */
};
@@ -603,6 +719,27 @@ PyInit_signal(void)
goto finally;
Py_DECREF(x);
+#ifdef SIG_BLOCK
+ x = PyLong_FromLong(SIG_BLOCK);
+ if (!x || PyDict_SetItemString(d, "SIG_BLOCK", x) < 0)
+ goto finally;
+ Py_DECREF(x);
+#endif
+
+#ifdef SIG_UNBLOCK
+ x = PyLong_FromLong(SIG_UNBLOCK);
+ if (!x || PyDict_SetItemString(d, "SIG_UNBLOCK", x) < 0)
+ goto finally;
+ Py_DECREF(x);
+#endif
+
+#ifdef SIG_SETMASK
+ x = PyLong_FromLong(SIG_SETMASK);
+ if (!x || PyDict_SetItemString(d, "SIG_SETMASK", x) < 0)
+ goto finally;
+ Py_DECREF(x);
+#endif
+
x = IntHandler = PyDict_GetItemString(d, "default_int_handler");
if (!x)
goto finally;