summaryrefslogtreecommitdiff
path: root/Modules
diff options
context:
space:
mode:
authorAntoine Pitrou <pitrou@free.fr>2018-05-04 13:00:50 +0200
committerGitHub <noreply@github.com>2018-05-04 13:00:50 +0200
commit9d3627e311211a1b4abcda29c36fe4afe2c46532 (patch)
tree26f76c94bb55ee8b242f044efa26cfd8b08e9d26 /Modules
parent491bbedc209fea314a04cb3015da68fb0aa63238 (diff)
downloadcpython-git-9d3627e311211a1b4abcda29c36fe4afe2c46532.tar.gz
bpo-33332: Add signal.valid_signals() (GH-6581)
Diffstat (limited to 'Modules')
-rw-r--r--Modules/clinic/signalmodule.c.h31
-rw-r--r--Modules/signalmodule.c64
2 files changed, 89 insertions, 6 deletions
diff --git a/Modules/clinic/signalmodule.c.h b/Modules/clinic/signalmodule.c.h
index 1c439716c4..eca2da10ad 100644
--- a/Modules/clinic/signalmodule.c.h
+++ b/Modules/clinic/signalmodule.c.h
@@ -341,6 +341,31 @@ PyDoc_STRVAR(signal_sigwait__doc__,
#endif /* defined(HAVE_SIGWAIT) */
+#if (defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS))
+
+PyDoc_STRVAR(signal_valid_signals__doc__,
+"valid_signals($module, /)\n"
+"--\n"
+"\n"
+"Return a set of valid signal numbers on this platform.\n"
+"\n"
+"The signal numbers returned by this function can be safely passed to\n"
+"functions like `pthread_sigmask`.");
+
+#define SIGNAL_VALID_SIGNALS_METHODDEF \
+ {"valid_signals", (PyCFunction)signal_valid_signals, METH_NOARGS, signal_valid_signals__doc__},
+
+static PyObject *
+signal_valid_signals_impl(PyObject *module);
+
+static PyObject *
+signal_valid_signals(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ return signal_valid_signals_impl(module);
+}
+
+#endif /* (defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS)) */
+
#if defined(HAVE_SIGWAITINFO)
PyDoc_STRVAR(signal_sigwaitinfo__doc__,
@@ -459,6 +484,10 @@ exit:
#define SIGNAL_SIGWAIT_METHODDEF
#endif /* !defined(SIGNAL_SIGWAIT_METHODDEF) */
+#ifndef SIGNAL_VALID_SIGNALS_METHODDEF
+ #define SIGNAL_VALID_SIGNALS_METHODDEF
+#endif /* !defined(SIGNAL_VALID_SIGNALS_METHODDEF) */
+
#ifndef SIGNAL_SIGWAITINFO_METHODDEF
#define SIGNAL_SIGWAITINFO_METHODDEF
#endif /* !defined(SIGNAL_SIGWAITINFO_METHODDEF) */
@@ -470,4 +499,4 @@ exit:
#ifndef SIGNAL_PTHREAD_KILL_METHODDEF
#define SIGNAL_PTHREAD_KILL_METHODDEF
#endif /* !defined(SIGNAL_PTHREAD_KILL_METHODDEF) */
-/*[clinic end generated code: output=7b41486acf93aa8e input=a9049054013a1b77]*/
+/*[clinic end generated code: output=f35d79e0cfee3f1b input=a9049054013a1b77]*/
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index 35fd87e2d1..003bbb60e3 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -841,11 +841,21 @@ iterable_to_sigset(PyObject *iterable, sigset_t *mask)
if (signum == -1 && PyErr_Occurred())
goto error;
if (0 < signum && signum < NSIG) {
- /* bpo-33329: ignore sigaddset() return value as it can fail
- * for some reserved signals, but we want the `range(1, NSIG)`
- * idiom to allow selecting all valid signals.
- */
- (void) sigaddset(mask, (int)signum);
+ if (sigaddset(mask, (int)signum)) {
+ if (errno != EINVAL) {
+ /* Probably impossible */
+ PyErr_SetFromErrno(PyExc_OSError);
+ goto error;
+ }
+ /* For backwards compatibility, allow idioms such as
+ * `range(1, NSIG)` but warn about invalid signal numbers
+ */
+ const char *msg =
+ "invalid signal number %ld, please use valid_signals()";
+ if (PyErr_WarnFormat(PyExc_RuntimeWarning, 1, msg, signum)) {
+ goto error;
+ }
+ }
}
else {
PyErr_Format(PyExc_ValueError,
@@ -1001,6 +1011,47 @@ signal_sigwait(PyObject *module, PyObject *sigset)
#endif /* #ifdef HAVE_SIGWAIT */
+#if defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS)
+
+/*[clinic input]
+signal.valid_signals
+
+Return a set of valid signal numbers on this platform.
+
+The signal numbers returned by this function can be safely passed to
+functions like `pthread_sigmask`.
+[clinic start generated code]*/
+
+static PyObject *
+signal_valid_signals_impl(PyObject *module)
+/*[clinic end generated code: output=1609cffbcfcf1314 input=86a3717ff25288f2]*/
+{
+#ifdef MS_WINDOWS
+#ifdef SIGBREAK
+ PyObject *tup = Py_BuildValue("(iiiiiii)", SIGABRT, SIGBREAK, SIGFPE,
+ SIGILL, SIGINT, SIGSEGV, SIGTERM);
+#else
+ PyObject *tup = Py_BuildValue("(iiiiii)", SIGABRT, SIGFPE, SIGILL,
+ SIGINT, SIGSEGV, SIGTERM);
+#endif
+ if (tup == NULL) {
+ return NULL;
+ }
+ PyObject *set = PySet_New(tup);
+ Py_DECREF(tup);
+ return set;
+#else
+ sigset_t mask;
+ if (sigemptyset(&mask) || sigfillset(&mask)) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ return sigset_to_set(mask);
+#endif
+}
+
+#endif /* #if defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS) */
+
+
#if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT)
static int initialized;
static PyStructSequence_Field struct_siginfo_fields[] = {
@@ -1225,6 +1276,9 @@ static PyMethodDef signal_methods[] = {
SIGNAL_SIGWAIT_METHODDEF
SIGNAL_SIGWAITINFO_METHODDEF
SIGNAL_SIGTIMEDWAIT_METHODDEF
+#if defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS)
+ SIGNAL_VALID_SIGNALS_METHODDEF
+#endif
{NULL, NULL} /* sentinel */
};