The following are my changes in signalmodule.c
static PyObject *
signal_mysignal_impl(PyObject *module, int signalnum, PyObject *handler)
/*[clinic end generated code: output=b44cfda43780f3a1 input=deee84af5fa0432c]*/
{
_signal_module_state *modstate = get_signal_state(module);
PyObject *old_handler;
void (*func)(int);
#ifdef MS_WINDOWS
/* Validate that signalnum is one of the allowable signals */
switch (signalnum) {
case SIGABRT: break;
#ifdef SIGBREAK
/* Issue #10003: SIGBREAK is not documented as permitted, but works
and corresponds to CTRL_BREAK_EVENT. */
case SIGBREAK: break;
#endif
case SIGFPE: break;
case SIGILL: break;
case SIGINT: break;
case SIGSEGV: break;
case SIGTERM: break;
default:
PyErr_SetString(PyExc_ValueError, "invalid signal value");
return NULL;
}
#endif
PyThreadState *tstate = _PyThreadState_GET();
if (!_Py_ThreadCanHandleSignals(tstate->interp)) {
_PyErr_SetString(tstate, PyExc_ValueError,
"signal only works in main thread "
"of the main interpreter");
return NULL;
}
if (signalnum < 1 || signalnum >= Py_NSIG) {
_PyErr_SetString(tstate, PyExc_ValueError,
"signal number out of range");
return NULL;
}
if (PyCallable_Check(handler)) {
func = signal_handler;
}
else if (compare_handler(handler, modstate->ignore_handler))
{
func = SIG_IGN;
}
else if (compare_handler(handler, modstate->default_handler))
{
func = SIG_DFL;
} else {
_PyErr_SetString(tstate, PyExc_TypeError,
"signal handler must be signal.SIG_IGN, "
"signal.SIG_DFL, or a callable object");
return NULL;
}
/* Check for pending signals before changing signal handler */
if (_PyErr_CheckSignalsTstate(tstate)) {
return NULL;
}
if (my_setsig(signalnum, func) == SIG_ERR) { // The only change with respect to signal_signal_impl is this function instead of PyOS_setsig
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
old_handler = get_handler(signalnum);
set_handler(signalnum, Py_NewRef(handler));
if (old_handler != NULL) {
return old_handler;
}
else {
Py_RETURN_NONE;
}
}
I have added this method’s inclusion in this struct
static PyMethodDef signal_methods[] = {
SIGNAL_DEFAULT_INT_HANDLER_METHODDEF
SIGNAL_ALARM_METHODDEF
SIGNAL_SETITIMER_METHODDEF
SIGNAL_GETITIMER_METHODDEF
SIGNAL_SIGNAL_METHODDEF
SIGNAL_MYSIGNAL_METHODDEF
SIGNAL_RAISE_SIGNAL_METHODDEF
SIGNAL_STRSIGNAL_METHODDEF
SIGNAL_GETSIGNAL_METHODDEF
{"set_wakeup_fd", _PyCFunction_CAST(signal_set_wakeup_fd), METH_VARARGS | METH_KEYWORDS, set_wakeup_fd_doc},
SIGNAL_SIGINTERRUPT_METHODDEF
SIGNAL_PAUSE_METHODDEF
SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF
SIGNAL_PTHREAD_KILL_METHODDEF
SIGNAL_PTHREAD_SIGMASK_METHODDEF
SIGNAL_SIGPENDING_METHODDEF
SIGNAL_SIGWAIT_METHODDEF
SIGNAL_SIGWAITINFO_METHODDEF
SIGNAL_SIGTIMEDWAIT_METHODDEF
#if defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS)
SIGNAL_VALID_SIGNALS_METHODDEF
#endif
{NULL, NULL} /* sentinel */
};
The following are my changes in Modules/clinic/signalmodule.c.h
PyDoc_STRVAR(signal_mysignal__doc__,
"mysignal($module, signalnum, handler, /)\n"
"--\n"
"\n"
"Set the action for the given signal.\n"
"\n"
"The action can be SIG_DFL, SIG_IGN, or a callable Python object.\n"
"The previous action is returned. See getsignal() for possible return values.\n"
"\n"
"*** IMPORTANT NOTICE ***\n"
"A signal handler function is called with two arguments:\n"
"the first is the signal number, the second is the interrupted stack frame.");
#define SIGNAL_MYSIGNAL_METHODDEF \
{"mysignal", _PyCFunction_CAST(signal_mysignal), METH_FASTCALL, signal_mysignal__doc__},
static PyObject *
signal_mysignal_impl(PyObject *module, int signalnum, PyObject *handler);
static PyObject *
signal_mysignal(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
int signalnum;
PyObject *handler;
if (!_PyArg_CheckPositional("mysignal", nargs, 2, 2)) {
goto exit;
}
signalnum = _PyLong_AsInt(args[0]);
if (signalnum == -1 && PyErr_Occurred()) {
goto exit;
}
handler = args[1];
return_value = signal_mysignal_impl(module, signalnum, handler);
exit:
return return_value;
}