diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst index 67eaa2c6381..3f17e08f0f9 100644 --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -207,6 +207,15 @@ The :mod:`signal` module defines the following functions: installed from Python. +.. function:: strsignal(signalnum) + + Return the system description of the signal *signalnum*, such as + "Interrupt", "Segmentation fault", etc. Returns :const:`None` if the signal + is not recognized. + + .. versionadded:: 3.8 + + .. function:: pause() Cause the process to sleep until a signal is received; the appropriate handler diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 48b7a392e50..fbb12a5b67b 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -43,6 +43,8 @@ class PosixTests(unittest.TestCase): self.assertRaises(ValueError, signal.signal, 4242, self.trivial_signal_handler) + self.assertRaises(ValueError, signal.strsignal, 4242) + def test_setting_signal_handler_to_none_raises_error(self): self.assertRaises(TypeError, signal.signal, signal.SIGUSR1, None) @@ -55,6 +57,10 @@ class PosixTests(unittest.TestCase): signal.signal(signal.SIGHUP, hup) self.assertEqual(signal.getsignal(signal.SIGHUP), hup) + def test_strsignal(self): + self.assertEqual(signal.strsignal(signal.SIGINT), "Interrupt") + self.assertEqual(signal.strsignal(signal.SIGTERM), "Terminated") + # Issue 3864, unknown if this affects earlier versions of freebsd also def test_interprocess_signal(self): dirname = os.path.dirname(__file__) diff --git a/Misc/NEWS.d/next/Library/2018-03-07-19-37-00.bpo-22674.2sIMmM.rst b/Misc/NEWS.d/next/Library/2018-03-07-19-37-00.bpo-22674.2sIMmM.rst new file mode 100644 index 00000000000..a9af5da46ef --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-03-07-19-37-00.bpo-22674.2sIMmM.rst @@ -0,0 +1,2 @@ +Add the strsignal() function in the signal module that returns the system +description of the given signal, as returned by strsignal(3). diff --git a/Modules/clinic/signalmodule.c.h b/Modules/clinic/signalmodule.c.h index dc3aadf878b..1c439716c49 100644 --- a/Modules/clinic/signalmodule.c.h +++ b/Modules/clinic/signalmodule.c.h @@ -129,6 +129,36 @@ exit: return return_value; } +PyDoc_STRVAR(signal_strsignal__doc__, +"strsignal($module, signalnum, /)\n" +"--\n" +"\n" +"Return the system description of the given signal.\n" +"\n" +"The return values can be such as \"Interrupt\", \"Segmentation fault\", etc.\n" +"Returns None if the signal is not recognized."); + +#define SIGNAL_STRSIGNAL_METHODDEF \ + {"strsignal", (PyCFunction)signal_strsignal, METH_O, signal_strsignal__doc__}, + +static PyObject * +signal_strsignal_impl(PyObject *module, int signalnum); + +static PyObject * +signal_strsignal(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + int signalnum; + + if (!PyArg_Parse(arg, "i:strsignal", &signalnum)) { + goto exit; + } + return_value = signal_strsignal_impl(module, signalnum); + +exit: + return return_value; +} + #if defined(HAVE_SIGINTERRUPT) PyDoc_STRVAR(signal_siginterrupt__doc__, @@ -440,4 +470,4 @@ exit: #ifndef SIGNAL_PTHREAD_KILL_METHODDEF #define SIGNAL_PTHREAD_KILL_METHODDEF #endif /* !defined(SIGNAL_PTHREAD_KILL_METHODDEF) */ -/*[clinic end generated code: output=36132f4189381fe0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7b41486acf93aa8e input=a9049054013a1b77]*/ diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index b553eedc0f2..79161601438 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -504,6 +504,66 @@ signal_getsignal_impl(PyObject *module, int signalnum) } } + +/*[clinic input] +signal.strsignal + + signalnum: int + / + +Return the system description of the given signal. + +The return values can be such as "Interrupt", "Segmentation fault", etc. +Returns None if the signal is not recognized. +[clinic start generated code]*/ + +static PyObject * +signal_strsignal_impl(PyObject *module, int signalnum) +/*[clinic end generated code: output=44e12e1e3b666261 input=b77914b03f856c74]*/ +{ + char *res; + + if (signalnum < 1 || signalnum >= NSIG) { + PyErr_SetString(PyExc_ValueError, + "signal number out of range"); + return NULL; + } + +#ifdef MS_WINDOWS + /* Custom redefinition of POSIX signals allowed on Windows */ + switch (signalnum) { + case SIGINT: + res = "Interrupt"; + break; + case SIGILL: + res = "Illegal instruction"; + break; + case SIGABRT: + res = "Aborted"; + break; + case SIGFPE: + res = "Floating point exception"; + break; + case SIGSEGV: + res = "Segmentation fault"; + break; + case SIGTERM: + res = "Terminated"; + break; + default: + Py_RETURN_NONE; + } +#else + errno = 0; + res = strsignal(signalnum); + + if (errno || res == NULL || strstr(res, "Unknown signal") != NULL) + Py_RETURN_NONE; +#endif + + return Py_BuildValue("s", res); +} + #ifdef HAVE_SIGINTERRUPT /*[clinic input] @@ -1152,6 +1212,7 @@ static PyMethodDef signal_methods[] = { SIGNAL_SETITIMER_METHODDEF SIGNAL_GETITIMER_METHODDEF SIGNAL_SIGNAL_METHODDEF + SIGNAL_STRSIGNAL_METHODDEF SIGNAL_GETSIGNAL_METHODDEF {"set_wakeup_fd", (PyCFunction)signal_set_wakeup_fd, METH_VARARGS | METH_KEYWORDS, set_wakeup_fd_doc}, SIGNAL_SIGINTERRUPT_METHODDEF