Skip to content

Commit

Permalink
pythonGH-98023: Change default child watcher to PidfdChildWatcher on …
Browse files Browse the repository at this point in the history
…supported systems (python#98024)
  • Loading branch information
kumaraditya303 authored and mpage committed Oct 11, 2022
1 parent 6cd489d commit 776f894
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 2 deletions.
16 changes: 15 additions & 1 deletion Lib/asyncio/unix_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,17 @@ def _do_waitpid(self, loop, expected_pid, callback, args):

self._threads.pop(expected_pid)

def can_use_pidfd():
if not hasattr(os, 'pidfd_open'):
return False
try:
pid = os.getpid()
os.close(os.pidfd_open(pid, 0))
except OSError:
# blocked by security policy like SECCOMP
return False
return True


class _UnixDefaultEventLoopPolicy(events.BaseDefaultEventLoopPolicy):
"""UNIX event loop policy with a watcher for child processes."""
Expand All @@ -1415,7 +1426,10 @@ def __init__(self):
def _init_watcher(self):
with events._lock:
if self._watcher is None: # pragma: no branch
self._watcher = ThreadedChildWatcher()
if can_use_pidfd():
self._watcher = PidfdChildWatcher()
else:
self._watcher = ThreadedChildWatcher()
if threading.current_thread() is threading.main_thread():
self._watcher.attach_loop(self._local._loop)

Expand Down
14 changes: 13 additions & 1 deletion Lib/test/test_asyncio/test_unix_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -1702,14 +1702,26 @@ def create_policy(self):
def test_get_default_child_watcher(self):
policy = self.create_policy()
self.assertIsNone(policy._watcher)

unix_events.can_use_pidfd = mock.Mock()
unix_events.can_use_pidfd.return_value = False
watcher = policy.get_child_watcher()
self.assertIsInstance(watcher, asyncio.ThreadedChildWatcher)

self.assertIs(policy._watcher, watcher)

self.assertIs(watcher, policy.get_child_watcher())

policy = self.create_policy()
self.assertIsNone(policy._watcher)
unix_events.can_use_pidfd = mock.Mock()
unix_events.can_use_pidfd.return_value = True
watcher = policy.get_child_watcher()
self.assertIsInstance(watcher, asyncio.PidfdChildWatcher)

self.assertIs(policy._watcher, watcher)

self.assertIs(watcher, policy.get_child_watcher())

def test_get_child_watcher_after_set(self):
policy = self.create_policy()
watcher = asyncio.FastChildWatcher()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Change default child watcher to :class:`~asyncio.PidfdChildWatcher` on Linux systems which supports it. Patch by Kumar Aditya.

0 comments on commit 776f894

Please sign in to comment.