diff options
author | Victor Stinner <victor.stinner@haypocalc.com> | 2011-04-30 13:21:58 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@haypocalc.com> | 2011-04-30 13:21:58 (GMT) |
commit | a92933596156337cc004027e41073db6d68616b9 (patch) | |
tree | 581f92c46d9bb5302e5dc49007b2998a58ac19e8 /Modules/signalmodule.c | |
parent | d5c355ccc70d011ef2010537838d9a82e24b2b80 (diff) | |
download | cpython-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.c | 139 |
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; |