Skip to content

Commit 5d2a27d

Browse files
seirlvajrasky
authored andcommitted
signal: add strsignal() (#6017)
Co-authored-by: Vajrasky Kok <[email protected]>
1 parent 4484f9d commit 5d2a27d

File tree

5 files changed

+109
-1
lines changed

5 files changed

+109
-1
lines changed

Doc/library/signal.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,15 @@ The :mod:`signal` module defines the following functions:
207207
installed from Python.
208208

209209

210+
.. function:: strsignal(signalnum)
211+
212+
Return the system description of the signal *signalnum*, such as
213+
"Interrupt", "Segmentation fault", etc. Returns :const:`None` if the signal
214+
is not recognized.
215+
216+
.. versionadded:: 3.8
217+
218+
210219
.. function:: pause()
211220

212221
Cause the process to sleep until a signal is received; the appropriate handler

Lib/test/test_signal.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def test_out_of_range_signal_number_raises_error(self):
4343
self.assertRaises(ValueError, signal.signal, 4242,
4444
self.trivial_signal_handler)
4545

46+
self.assertRaises(ValueError, signal.strsignal, 4242)
47+
4648
def test_setting_signal_handler_to_none_raises_error(self):
4749
self.assertRaises(TypeError, signal.signal,
4850
signal.SIGUSR1, None)
@@ -55,6 +57,10 @@ def test_getsignal(self):
5557
signal.signal(signal.SIGHUP, hup)
5658
self.assertEqual(signal.getsignal(signal.SIGHUP), hup)
5759

60+
def test_strsignal(self):
61+
self.assertEqual(signal.strsignal(signal.SIGINT), "Interrupt")
62+
self.assertEqual(signal.strsignal(signal.SIGTERM), "Terminated")
63+
5864
# Issue 3864, unknown if this affects earlier versions of freebsd also
5965
def test_interprocess_signal(self):
6066
dirname = os.path.dirname(__file__)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add the strsignal() function in the signal module that returns the system
2+
description of the given signal, as returned by strsignal(3).

Modules/clinic/signalmodule.c.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,36 @@ signal_getsignal(PyObject *module, PyObject *arg)
129129
return return_value;
130130
}
131131

132+
PyDoc_STRVAR(signal_strsignal__doc__,
133+
"strsignal($module, signalnum, /)\n"
134+
"--\n"
135+
"\n"
136+
"Return the system description of the given signal.\n"
137+
"\n"
138+
"The return values can be such as \"Interrupt\", \"Segmentation fault\", etc.\n"
139+
"Returns None if the signal is not recognized.");
140+
141+
#define SIGNAL_STRSIGNAL_METHODDEF \
142+
{"strsignal", (PyCFunction)signal_strsignal, METH_O, signal_strsignal__doc__},
143+
144+
static PyObject *
145+
signal_strsignal_impl(PyObject *module, int signalnum);
146+
147+
static PyObject *
148+
signal_strsignal(PyObject *module, PyObject *arg)
149+
{
150+
PyObject *return_value = NULL;
151+
int signalnum;
152+
153+
if (!PyArg_Parse(arg, "i:strsignal", &signalnum)) {
154+
goto exit;
155+
}
156+
return_value = signal_strsignal_impl(module, signalnum);
157+
158+
exit:
159+
return return_value;
160+
}
161+
132162
#if defined(HAVE_SIGINTERRUPT)
133163

134164
PyDoc_STRVAR(signal_siginterrupt__doc__,
@@ -440,4 +470,4 @@ signal_pthread_kill(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
440470
#ifndef SIGNAL_PTHREAD_KILL_METHODDEF
441471
#define SIGNAL_PTHREAD_KILL_METHODDEF
442472
#endif /* !defined(SIGNAL_PTHREAD_KILL_METHODDEF) */
443-
/*[clinic end generated code: output=36132f4189381fe0 input=a9049054013a1b77]*/
473+
/*[clinic end generated code: output=7b41486acf93aa8e input=a9049054013a1b77]*/

Modules/signalmodule.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,66 @@ signal_getsignal_impl(PyObject *module, int signalnum)
504504
}
505505
}
506506

507+
508+
/*[clinic input]
509+
signal.strsignal
510+
511+
signalnum: int
512+
/
513+
514+
Return the system description of the given signal.
515+
516+
The return values can be such as "Interrupt", "Segmentation fault", etc.
517+
Returns None if the signal is not recognized.
518+
[clinic start generated code]*/
519+
520+
static PyObject *
521+
signal_strsignal_impl(PyObject *module, int signalnum)
522+
/*[clinic end generated code: output=44e12e1e3b666261 input=b77914b03f856c74]*/
523+
{
524+
char *res;
525+
526+
if (signalnum < 1 || signalnum >= NSIG) {
527+
PyErr_SetString(PyExc_ValueError,
528+
"signal number out of range");
529+
return NULL;
530+
}
531+
532+
#ifdef MS_WINDOWS
533+
/* Custom redefinition of POSIX signals allowed on Windows */
534+
switch (signalnum) {
535+
case SIGINT:
536+
res = "Interrupt";
537+
break;
538+
case SIGILL:
539+
res = "Illegal instruction";
540+
break;
541+
case SIGABRT:
542+
res = "Aborted";
543+
break;
544+
case SIGFPE:
545+
res = "Floating point exception";
546+
break;
547+
case SIGSEGV:
548+
res = "Segmentation fault";
549+
break;
550+
case SIGTERM:
551+
res = "Terminated";
552+
break;
553+
default:
554+
Py_RETURN_NONE;
555+
}
556+
#else
557+
errno = 0;
558+
res = strsignal(signalnum);
559+
560+
if (errno || res == NULL || strstr(res, "Unknown signal") != NULL)
561+
Py_RETURN_NONE;
562+
#endif
563+
564+
return Py_BuildValue("s", res);
565+
}
566+
507567
#ifdef HAVE_SIGINTERRUPT
508568

509569
/*[clinic input]
@@ -1152,6 +1212,7 @@ static PyMethodDef signal_methods[] = {
11521212
SIGNAL_SETITIMER_METHODDEF
11531213
SIGNAL_GETITIMER_METHODDEF
11541214
SIGNAL_SIGNAL_METHODDEF
1215+
SIGNAL_STRSIGNAL_METHODDEF
11551216
SIGNAL_GETSIGNAL_METHODDEF
11561217
{"set_wakeup_fd", (PyCFunction)signal_set_wakeup_fd, METH_VARARGS | METH_KEYWORDS, set_wakeup_fd_doc},
11571218
SIGNAL_SIGINTERRUPT_METHODDEF

0 commit comments

Comments
 (0)