mirror of https://github.com/python/cpython
closes bpo-38712: Add signal.pidfd_send_signal. (GH-17070)
This exposes a Linux-specific syscall for sending a signal to a process identified by a file descriptor rather than a pid. For simplicity, we don't support the siginfo_t parameter to the syscall. This parameter allows implementing a pidfd version of rt_sigqueueinfo(2), which Python also doesn't support.
This commit is contained in:
parent
be143ec996
commit
7483451577
|
@ -247,6 +247,19 @@ The :mod:`signal` module defines the following functions:
|
||||||
.. versionadded:: 3.8
|
.. versionadded:: 3.8
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: pidfd_send_signal(pidfd, sig, siginfo=None, flags=0)
|
||||||
|
|
||||||
|
Send signal *sig* to the process referred to by file descriptor *pidfd*.
|
||||||
|
Python does not currently support the *siginfo* parameter; it must be
|
||||||
|
``None``. The *flags* argument is provided for future extensions; no flag
|
||||||
|
values are currently defined.
|
||||||
|
|
||||||
|
See the :manpage:`pidfd_send_signal(2)` man page for more information.
|
||||||
|
|
||||||
|
.. availability:: Linux 5.1+
|
||||||
|
.. versionadded:: 3.9
|
||||||
|
|
||||||
|
|
||||||
.. function:: pthread_kill(thread_id, signalnum)
|
.. function:: pthread_kill(thread_id, signalnum)
|
||||||
|
|
||||||
Send the signal *signalnum* to the thread *thread_id*, another thread in the
|
Send the signal *signalnum* to the thread *thread_id*, another thread in the
|
||||||
|
|
|
@ -197,6 +197,13 @@ now raises :exc:`ImportError` instead of :exc:`ValueError` for invalid relative
|
||||||
import attempts.
|
import attempts.
|
||||||
(Contributed by Ngalim Siregar in :issue:`37444`.)
|
(Contributed by Ngalim Siregar in :issue:`37444`.)
|
||||||
|
|
||||||
|
signal
|
||||||
|
------
|
||||||
|
|
||||||
|
Exposed the Linux-specific :func:`signal.pidfd_send_signal` for sending to
|
||||||
|
signals to a process using a file descriptor instead of a pid. (:issue:`38712`)
|
||||||
|
|
||||||
|
|
||||||
Optimizations
|
Optimizations
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -1273,6 +1273,25 @@ class RaiseSignalTest(unittest.TestCase):
|
||||||
self.assertTrue(is_ok)
|
self.assertTrue(is_ok)
|
||||||
|
|
||||||
|
|
||||||
|
class PidfdSignalTest(unittest.TestCase):
|
||||||
|
|
||||||
|
@unittest.skipUnless(
|
||||||
|
hasattr(signal, "pidfd_send_signal"),
|
||||||
|
"pidfd support not built in",
|
||||||
|
)
|
||||||
|
def test_pidfd_send_signal(self):
|
||||||
|
with self.assertRaises(OSError) as cm:
|
||||||
|
signal.pidfd_send_signal(0, signal.SIGINT)
|
||||||
|
if cm.exception.errno == errno.ENOSYS:
|
||||||
|
self.skipTest("kernel does not support pidfds")
|
||||||
|
self.assertEqual(cm.exception.errno, errno.EBADF)
|
||||||
|
my_pidfd = os.open(f'/proc/{os.getpid()}', os.O_DIRECTORY)
|
||||||
|
self.addCleanup(os.close, my_pidfd)
|
||||||
|
with self.assertRaisesRegexp(TypeError, "^siginfo must be None$"):
|
||||||
|
signal.pidfd_send_signal(my_pidfd, signal.SIGINT, object(), 0)
|
||||||
|
with self.assertRaises(KeyboardInterrupt):
|
||||||
|
signal.pidfd_send_signal(my_pidfd, signal.SIGINT)
|
||||||
|
|
||||||
def tearDownModule():
|
def tearDownModule():
|
||||||
support.reap_children()
|
support.reap_children()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Add the Linux-specific :func:`signal.pidfd_send_signal` function, which
|
||||||
|
allows sending a signal to a process identified by a file descriptor rather
|
||||||
|
than a pid.
|
|
@ -611,6 +611,76 @@ exit:
|
||||||
|
|
||||||
#endif /* defined(HAVE_PTHREAD_KILL) */
|
#endif /* defined(HAVE_PTHREAD_KILL) */
|
||||||
|
|
||||||
|
#if (defined(__linux__) && defined(__NR_pidfd_send_signal))
|
||||||
|
|
||||||
|
PyDoc_STRVAR(signal_pidfd_send_signal__doc__,
|
||||||
|
"pidfd_send_signal($module, pidfd, signalnum, siginfo=None, flags=0, /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Send a signal to a process referred to by a pid file descriptor.");
|
||||||
|
|
||||||
|
#define SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF \
|
||||||
|
{"pidfd_send_signal", (PyCFunction)(void(*)(void))signal_pidfd_send_signal, METH_FASTCALL, signal_pidfd_send_signal__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
signal_pidfd_send_signal_impl(PyObject *module, int pidfd, int signalnum,
|
||||||
|
PyObject *siginfo, int flags);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
signal_pidfd_send_signal(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
int pidfd;
|
||||||
|
int signalnum;
|
||||||
|
PyObject *siginfo = Py_None;
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
if (!_PyArg_CheckPositional("pidfd_send_signal", nargs, 2, 4)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (PyFloat_Check(args[0])) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"integer argument expected, got float" );
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
pidfd = _PyLong_AsInt(args[0]);
|
||||||
|
if (pidfd == -1 && PyErr_Occurred()) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (PyFloat_Check(args[1])) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"integer argument expected, got float" );
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
signalnum = _PyLong_AsInt(args[1]);
|
||||||
|
if (signalnum == -1 && PyErr_Occurred()) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (nargs < 3) {
|
||||||
|
goto skip_optional;
|
||||||
|
}
|
||||||
|
siginfo = args[2];
|
||||||
|
if (nargs < 4) {
|
||||||
|
goto skip_optional;
|
||||||
|
}
|
||||||
|
if (PyFloat_Check(args[3])) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"integer argument expected, got float" );
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
flags = _PyLong_AsInt(args[3]);
|
||||||
|
if (flags == -1 && PyErr_Occurred()) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
skip_optional:
|
||||||
|
return_value = signal_pidfd_send_signal_impl(module, pidfd, signalnum, siginfo, flags);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* (defined(__linux__) && defined(__NR_pidfd_send_signal)) */
|
||||||
|
|
||||||
#ifndef SIGNAL_ALARM_METHODDEF
|
#ifndef SIGNAL_ALARM_METHODDEF
|
||||||
#define SIGNAL_ALARM_METHODDEF
|
#define SIGNAL_ALARM_METHODDEF
|
||||||
#endif /* !defined(SIGNAL_ALARM_METHODDEF) */
|
#endif /* !defined(SIGNAL_ALARM_METHODDEF) */
|
||||||
|
@ -658,4 +728,8 @@ exit:
|
||||||
#ifndef SIGNAL_PTHREAD_KILL_METHODDEF
|
#ifndef SIGNAL_PTHREAD_KILL_METHODDEF
|
||||||
#define SIGNAL_PTHREAD_KILL_METHODDEF
|
#define SIGNAL_PTHREAD_KILL_METHODDEF
|
||||||
#endif /* !defined(SIGNAL_PTHREAD_KILL_METHODDEF) */
|
#endif /* !defined(SIGNAL_PTHREAD_KILL_METHODDEF) */
|
||||||
/*[clinic end generated code: output=3320b8f73c20ba60 input=a9049054013a1b77]*/
|
|
||||||
|
#ifndef SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF
|
||||||
|
#define SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF
|
||||||
|
#endif /* !defined(SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF) */
|
||||||
|
/*[clinic end generated code: output=b41b4b6bd9ad4da2 input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
#ifdef HAVE_SIGNAL_H
|
#ifdef HAVE_SIGNAL_H
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_SYS_SYSCALL_H
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -1250,6 +1253,38 @@ signal_pthread_kill_impl(PyObject *module, unsigned long thread_id,
|
||||||
#endif /* #if defined(HAVE_PTHREAD_KILL) */
|
#endif /* #if defined(HAVE_PTHREAD_KILL) */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__linux__) && defined(__NR_pidfd_send_signal)
|
||||||
|
/*[clinic input]
|
||||||
|
signal.pidfd_send_signal
|
||||||
|
|
||||||
|
pidfd: int
|
||||||
|
signalnum: int
|
||||||
|
siginfo: object = None
|
||||||
|
flags: int = 0
|
||||||
|
/
|
||||||
|
|
||||||
|
Send a signal to a process referred to by a pid file descriptor.
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
signal_pidfd_send_signal_impl(PyObject *module, int pidfd, int signalnum,
|
||||||
|
PyObject *siginfo, int flags)
|
||||||
|
/*[clinic end generated code: output=2d59f04a75d9cbdf input=2a6543a1f4ac2000]*/
|
||||||
|
|
||||||
|
{
|
||||||
|
if (siginfo != Py_None) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "siginfo must be None");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (syscall(__NR_pidfd_send_signal, pidfd, signalnum, NULL, flags) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* List of functions defined in the module -- some of the methoddefs are
|
/* List of functions defined in the module -- some of the methoddefs are
|
||||||
defined to nothing if the corresponding C function is not available. */
|
defined to nothing if the corresponding C function is not available. */
|
||||||
|
@ -1265,6 +1300,7 @@ static PyMethodDef signal_methods[] = {
|
||||||
{"set_wakeup_fd", (PyCFunction)(void(*)(void))signal_set_wakeup_fd, METH_VARARGS | METH_KEYWORDS, set_wakeup_fd_doc},
|
{"set_wakeup_fd", (PyCFunction)(void(*)(void))signal_set_wakeup_fd, METH_VARARGS | METH_KEYWORDS, set_wakeup_fd_doc},
|
||||||
SIGNAL_SIGINTERRUPT_METHODDEF
|
SIGNAL_SIGINTERRUPT_METHODDEF
|
||||||
SIGNAL_PAUSE_METHODDEF
|
SIGNAL_PAUSE_METHODDEF
|
||||||
|
SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF
|
||||||
SIGNAL_PTHREAD_KILL_METHODDEF
|
SIGNAL_PTHREAD_KILL_METHODDEF
|
||||||
SIGNAL_PTHREAD_SIGMASK_METHODDEF
|
SIGNAL_PTHREAD_SIGMASK_METHODDEF
|
||||||
SIGNAL_SIGPENDING_METHODDEF
|
SIGNAL_SIGPENDING_METHODDEF
|
||||||
|
|
Loading…
Reference in New Issue