Skip to content

bpo-38692: Add os.pidfd_open. #17063

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Doc/library/os.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions Doc/whatsnew/3.9.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
---------

Expand Down
9 changes: 9 additions & 0 deletions Lib/test/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to remove ", 0" flags and add a few more tests:

pid = os.pidfd_open(os.getpid())
try:
    self.assertIsInstance(pid, int)
    self.assertGreaterEqual(pid, 0)
finally:
    os.close(pid)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I pass 0 is to make sure the flags argument exists and "works".

I don't think your other suggested tests add much value. Calling close on such an invalid value will probably fail anyway.


class PosixGroupsTester(unittest.TestCase):

def setUp(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Expose the Linux ``pidfd_open`` syscall as :func:`os.pidfd_open`.
44 changes: 43 additions & 1 deletion Modules/clinic/posixmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down