[Python-checkins] bpo-38692: Add os.pidfd_open. (GH-17063)

Benjamin Peterson webhook-mailer at python.org
Tue Nov 5 22:21:44 EST 2019


https://github.com/python/cpython/commit/6c4c45efaeb40f4f837570f57d90a0b3429c6ae9
commit: 6c4c45efaeb40f4f837570f57d90a0b3429c6ae9
branch: master
author: Benjamin Peterson <benjamin at python.org>
committer: GitHub <noreply at github.com>
date: 2019-11-05T19:21:29-08:00
summary:

bpo-38692: Add os.pidfd_open. (GH-17063)

files:
A Misc/NEWS.d/next/Library/2019-11-05-07-18-24.bpo-38692.UpatA7.rst
M Doc/library/os.rst
M Doc/whatsnew/3.9.rst
M Lib/test/test_posix.py
M Modules/clinic/posixmodule.c.h
M Modules/posixmodule.c

diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index 8e9d9e6f034e3..9c907a7ee5911 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -3539,6 +3539,19 @@ written in Python, such as a mail server's external command delivery program.
    .. availability:: Unix.
 
 
+.. function:: pidfd_open(pid, flags=0)
+
+   Return a file descriptor referring to the process *pid*.  This descriptor can
+   be used to perform process management without races and signals.  The *flags*
+   argument is provided for future extensions; no flag values are currently
+   defined.
+
+   See the :manpage:`pidfd_open(2)` man page for more details.
+
+   .. availability:: Linux 5.3+
+   .. versionadded:: 3.9
+
+
 .. function:: plock(op)
 
    Lock program segments into memory.  The value of *op* (defined in
diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst
index 3cac9c5eedbc2..7e778058c8ded 100644
--- a/Doc/whatsnew/3.9.rst
+++ b/Doc/whatsnew/3.9.rst
@@ -150,6 +150,9 @@ os
 Added :data:`~os.CLD_KILLED` and :data:`~os.CLD_STOPPED` for :attr:`si_code`.
 (Contributed by Dong-hee Na in :issue:`38493`.)
 
+Exposed the Linux-specific :func:`os.pidfd_open` for process management with
+file descriptors. (:issue:`38692`)
+
 threading
 ---------
 
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
index 17e4ded2e2d69..98a39c3f04099 100644
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -1470,6 +1470,15 @@ def test_path_with_null_byte(self):
         open(fn, 'wb').close()
         self.assertRaises(ValueError, os.stat, fn_with_NUL)
 
+    @unittest.skipUnless(hasattr(os, "pidfd_open"), "pidfd_open unavailable")
+    def test_pidfd_open(self):
+        with self.assertRaises(OSError) as cm:
+            os.pidfd_open(-1)
+        if cm.exception.errno == errno.ENOSYS:
+            self.skipTest("system does not support pidfd_open")
+        self.assertEqual(cm.exception.errno, errno.EINVAL)
+        os.close(os.pidfd_open(os.getpid(), 0))
+
 class PosixGroupsTester(unittest.TestCase):
 
     def setUp(self):
diff --git a/Misc/NEWS.d/next/Library/2019-11-05-07-18-24.bpo-38692.UpatA7.rst b/Misc/NEWS.d/next/Library/2019-11-05-07-18-24.bpo-38692.UpatA7.rst
new file mode 100644
index 0000000000000..fd19c6f9eb52e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-11-05-07-18-24.bpo-38692.UpatA7.rst
@@ -0,0 +1 @@
+Expose the Linux ``pidfd_open`` syscall as :func:`os.pidfd_open`.
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index 3dada674fbab0..aa4756a620aae 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -3963,6 +3963,44 @@ os_wait(PyObject *module, PyObject *Py_UNUSED(ignored))
 
 #endif /* defined(HAVE_WAIT) */
 
+#if (defined(__linux__) && defined(__NR_pidfd_open))
+
+PyDoc_STRVAR(os_pidfd_open__doc__,
+"pidfd_open($module, /, pid, flags=0)\n"
+"--\n"
+"\n"
+"Return a file descriptor referring to the process *pid*.\n"
+"\n"
+"The descriptor can be used to perform process management without races and\n"
+"signals.");
+
+#define OS_PIDFD_OPEN_METHODDEF    \
+    {"pidfd_open", (PyCFunction)(void(*)(void))os_pidfd_open, METH_FASTCALL|METH_KEYWORDS, os_pidfd_open__doc__},
+
+static PyObject *
+os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags);
+
+static PyObject *
+os_pidfd_open(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    static const char * const _keywords[] = {"pid", "flags", NULL};
+    static _PyArg_Parser _parser = {"" _Py_PARSE_PID "|O&:pidfd_open", _keywords, 0};
+    pid_t pid;
+    unsigned int flags = 0;
+
+    if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
+        &pid, _PyLong_UnsignedInt_Converter, &flags)) {
+        goto exit;
+    }
+    return_value = os_pidfd_open_impl(module, pid, flags);
+
+exit:
+    return return_value;
+}
+
+#endif /* (defined(__linux__) && defined(__NR_pidfd_open)) */
+
 #if (defined(HAVE_READLINK) || defined(MS_WINDOWS))
 
 PyDoc_STRVAR(os_readlink__doc__,
@@ -8480,6 +8518,10 @@ os__remove_dll_directory(PyObject *module, PyObject *const *args, Py_ssize_t nar
     #define OS_WAIT_METHODDEF
 #endif /* !defined(OS_WAIT_METHODDEF) */
 
+#ifndef OS_PIDFD_OPEN_METHODDEF
+    #define OS_PIDFD_OPEN_METHODDEF
+#endif /* !defined(OS_PIDFD_OPEN_METHODDEF) */
+
 #ifndef OS_READLINK_METHODDEF
     #define OS_READLINK_METHODDEF
 #endif /* !defined(OS_READLINK_METHODDEF) */
@@ -8731,4 +8773,4 @@ os__remove_dll_directory(PyObject *module, PyObject *const *args, Py_ssize_t nar
 #ifndef OS__REMOVE_DLL_DIRECTORY_METHODDEF
     #define OS__REMOVE_DLL_DIRECTORY_METHODDEF
 #endif /* !defined(OS__REMOVE_DLL_DIRECTORY_METHODDEF) */
-/*[clinic end generated code: output=c6e67d475eef00c4 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=51ba5b9536420cea input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 6d837c6552f49..46cf7b2f55ac1 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -7861,6 +7861,30 @@ os_wait_impl(PyObject *module)
 }
 #endif /* HAVE_WAIT */
 
+#if defined(__linux__) && defined(__NR_pidfd_open)
+/*[clinic input]
+os.pidfd_open
+  pid: pid_t
+  flags: unsigned_int = 0
+
+Return a file descriptor referring to the process *pid*.
+
+The descriptor can be used to perform process management without races and
+signals.
+[clinic start generated code]*/
+
+static PyObject *
+os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags)
+/*[clinic end generated code: output=5c7252698947dc41 input=c3fd99ce947ccfef]*/
+{
+    int fd = syscall(__NR_pidfd_open, pid, flags);
+    if (fd < 0) {
+        return posix_error();
+    }
+    return PyLong_FromLong(fd);
+}
+#endif
+
 
 #if defined(HAVE_READLINK) || defined(MS_WINDOWS)
 /*[clinic input]
@@ -13671,6 +13695,7 @@ static PyMethodDef posix_methods[] = {
     OS_WAIT4_METHODDEF
     OS_WAITID_METHODDEF
     OS_WAITPID_METHODDEF
+    OS_PIDFD_OPEN_METHODDEF
     OS_GETSID_METHODDEF
     OS_SETSID_METHODDEF
     OS_SETPGID_METHODDEF



More information about the Python-checkins mailing list