Skip to content

Commit b081dd4

Browse files
authored
Merge branch 'main' into thread-hang-memory
2 parents b7bcba5 + 1692854 commit b081dd4

17 files changed

Lines changed: 288 additions & 29 deletions

Doc/library/os.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5062,6 +5062,18 @@ written in Python, such as a mail server's external command delivery program.
50625062
.. availability:: Linux >= 5.10
50635063
.. versionadded:: 3.12
50645064

5065+
.. function:: pidfd_getfd(pidfd, targetfd, *, flags=0)
5066+
5067+
Duplicate *targetfd* from the process referred to by the process file
5068+
descriptor *pidfd*, into the calling process. The returned file descriptor
5069+
is :ref:`non-inheritable <fd_inheritance>`.
5070+
5071+
*flags* is reserved, and currently must be ``0``.
5072+
5073+
See the :manpage:`pidfd_getfd(2)` man page for more details.
5074+
5075+
.. availability:: Linux >= 5.6, Android >= :func:`build-time <sys.getandroidapilevel>` API level 31
5076+
.. versionadded:: next
50655077

50665078
.. function:: plock(op, /)
50675079

Doc/whatsnew/3.16.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,12 @@ New modules
8686
Improved modules
8787
================
8888

89-
module_name
90-
-----------
89+
os
90+
--
9191

92-
* TODO
92+
* Add :func:`os.pidfd_getfd` for duplicating a file descriptor from another
93+
process via a pidfd. Available on Linux 5.6+.
94+
(Contributed by Maurycy Pawłowski-Wieroński in :gh:`149464`.)
9395

9496
.. Add improved modules above alphabetically, not here at the end.
9597

Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ struct _Py_global_strings {
713713
STRUCT_FOR_ID(person)
714714
STRUCT_FOR_ID(pi_factory)
715715
STRUCT_FOR_ID(pid)
716+
STRUCT_FOR_ID(pidfd)
716717
STRUCT_FOR_ID(pointer_bits)
717718
STRUCT_FOR_ID(policy)
718719
STRUCT_FOR_ID(pos)
@@ -831,6 +832,7 @@ struct _Py_global_strings {
831832
STRUCT_FOR_ID(take_bytes)
832833
STRUCT_FOR_ID(target)
833834
STRUCT_FOR_ID(target_is_directory)
835+
STRUCT_FOR_ID(targetfd)
834836
STRUCT_FOR_ID(task)
835837
STRUCT_FOR_ID(tb_frame)
836838
STRUCT_FOR_ID(tb_lasti)

Include/internal/pycore_runtime_init_generated.h

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_free_threading/test_dict.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,34 @@ def watcher():
268268
finally:
269269
_testcapi.clear_dict_watcher(wid)
270270

271+
def test_racing_split_dict_clear_and_lookup(self):
272+
class C:
273+
pass
274+
275+
keys = [f"a{i}" for i in range(16)]
276+
277+
def make_split_nonembedded():
278+
inst = C()
279+
for key in keys:
280+
setattr(inst, key, keys.index(key))
281+
# dict.copy() of a split instance dict yields a split table
282+
# with non-embedded values
283+
return inst.__dict__.copy()
284+
285+
d = make_split_nonembedded()
286+
287+
def clearer():
288+
for _ in range(1000):
289+
d.clear()
290+
d.update(make_split_nonembedded())
291+
292+
def reader():
293+
for _ in range(1000):
294+
for k in keys:
295+
d.get(k)
296+
297+
threading_helper.run_concurrently([clearer, reader, reader])
298+
271299
def test_racing_dict_update_and_method_lookup(self):
272300
# gh-144295: test race between dict modifications and method lookups.
273301
# Uses BytesIO because the race requires a type without Py_TPFLAGS_INLINE_VALUES

Lib/test/test_os/test_posix.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,6 +1604,34 @@ def test_pidfd_open(self):
16041604
self.assertEqual(cm.exception.errno, errno.EINVAL)
16051605
os.close(os.pidfd_open(os.getpid(), 0))
16061606

1607+
@unittest.skipUnless(hasattr(os, "pidfd_getfd"), "pidfd_getfd unavailable")
1608+
def test_pidfd_getfd(self):
1609+
fd = os.open(__file__, os.O_RDONLY)
1610+
self.addCleanup(os.close, fd)
1611+
pidfd = os.pidfd_open(os.getpid(), 0)
1612+
self.addCleanup(os.close, pidfd)
1613+
try:
1614+
dupfd = os.pidfd_getfd(pidfd, fd)
1615+
except OSError as exc:
1616+
if exc.errno == errno.ENOSYS:
1617+
self.skipTest("system does not support pidfd_getfd")
1618+
if isinstance(exc, PermissionError):
1619+
self.skipTest(f"pidfd_getfd syscall blocked: {exc!r}")
1620+
raise
1621+
self.addCleanup(os.close, dupfd)
1622+
1623+
self.assertFalse(os.get_inheritable(dupfd)) # PEP 446
1624+
self.assertEqual(os.fstat(fd), os.fstat(dupfd))
1625+
1626+
with self.assertRaises(OSError) as cm:
1627+
os.pidfd_getfd(-1, 0)
1628+
self.assertEqual(cm.exception.errno, errno.EBADF)
1629+
1630+
with self.assertRaises(OSError) as cm:
1631+
bad_fd = os_helper.make_bad_fd()
1632+
os.pidfd_getfd(pidfd, bad_fd)
1633+
self.assertEqual(cm.exception.errno, errno.EBADF)
1634+
16071635
@os_helper.skip_unless_hardlink
16081636
@os_helper.skip_unless_symlink
16091637
def test_link_follow_symlinks(self):

Lib/test/test_tkinter/test_misc.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import collections.abc
22
import functools
3+
import platform
4+
import sys
35
import unittest
46
import tkinter
57
from tkinter import TclError
@@ -578,12 +580,27 @@ def test_wm_attribute(self):
578580

579581
def test_wm_iconbitmap(self):
580582
t = tkinter.Toplevel(self.root)
583+
patchlevel = get_tk_patchlevel(t)
584+
585+
if (
586+
t._windowingsystem == 'aqua'
587+
and sys.platform == 'darwin'
588+
and platform.machine() == 'x86_64'
589+
and platform.mac_ver()[0].startswith('26.')
590+
and (
591+
patchlevel[:3] <= (8, 6, 17)
592+
or (9, 0) <= patchlevel[:3] <= (9, 0, 3)
593+
)
594+
):
595+
# https://github.com/python/cpython/issues/146531
596+
# Tk bug 4a2070f0d3a99aa412bc582d386d575ca2f37323
597+
self.skipTest('wm iconbitmap hangs on macOS 26 Intel')
598+
581599
self.assertEqual(t.wm_iconbitmap(), '')
582600
t.wm_iconbitmap('hourglass')
583601
bug = False
584602
if t._windowingsystem == 'aqua':
585603
# Tk bug 13ac26b35dc55f7c37f70b39d59d7ef3e63017c8.
586-
patchlevel = get_tk_patchlevel(t)
587604
if patchlevel < (8, 6, 17) or (9, 0) <= patchlevel < (9, 0, 2):
588605
bug = True
589606
if not bug:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add :func:`os.pidfd_getfd` for duplicating a file descriptor from another
2+
process via a pidfd. Available on Linux 5.6+. Patch by Maurycy
3+
Pawłowski-Wieroński.

0 commit comments

Comments
 (0)