@@ -912,46 +912,29 @@ class PidfdChildWatcher(AbstractChildWatcher):
912
912
recent (5.3+) kernels.
913
913
"""
914
914
915
- def __init__ (self ):
916
- self ._loop = None
917
- self ._callbacks = {}
918
-
919
915
def __enter__ (self ):
920
916
return self
921
917
922
918
def __exit__ (self , exc_type , exc_value , exc_traceback ):
923
919
pass
924
920
925
921
def is_active (self ):
926
- return self . _loop is not None and self . _loop . is_running ()
922
+ return True
927
923
928
924
def close (self ):
929
- self . attach_loop ( None )
925
+ pass
930
926
931
927
def attach_loop (self , loop ):
932
- if self ._loop is not None and loop is None and self ._callbacks :
933
- warnings .warn (
934
- 'A loop is being detached '
935
- 'from a child watcher with pending handlers' ,
936
- RuntimeWarning )
937
- for pidfd , _ , _ in self ._callbacks .values ():
938
- self ._loop ._remove_reader (pidfd )
939
- os .close (pidfd )
940
- self ._callbacks .clear ()
941
- self ._loop = loop
928
+ pass
942
929
943
930
def add_child_handler (self , pid , callback , * args ):
944
- existing = self ._callbacks .get (pid )
945
- if existing is not None :
946
- self ._callbacks [pid ] = existing [0 ], callback , args
947
- else :
948
- pidfd = os .pidfd_open (pid )
949
- self ._loop ._add_reader (pidfd , self ._do_wait , pid )
950
- self ._callbacks [pid ] = pidfd , callback , args
931
+ loop = events .get_running_loop ()
932
+ pidfd = os .pidfd_open (pid )
933
+ loop ._add_reader (pidfd , self ._do_wait , pid , pidfd , callback , args )
951
934
952
- def _do_wait (self , pid ):
953
- pidfd , callback , args = self . _callbacks . pop ( pid )
954
- self . _loop ._remove_reader (pidfd )
935
+ def _do_wait (self , pid , pidfd , callback , args ):
936
+ loop = events . get_running_loop ( )
937
+ loop ._remove_reader (pidfd )
955
938
try :
956
939
_ , status = os .waitpid (pid , 0 )
957
940
except ChildProcessError :
@@ -969,12 +952,9 @@ def _do_wait(self, pid):
969
952
callback (pid , returncode , * args )
970
953
971
954
def remove_child_handler (self , pid ):
972
- try :
973
- pidfd , _ , _ = self ._callbacks .pop (pid )
974
- except KeyError :
975
- return False
976
- self ._loop ._remove_reader (pidfd )
977
- os .close (pidfd )
955
+ # asyncio never calls remove_child_handler() !!!
956
+ # The method is no-op but is implemented because
957
+ # abstract base classes require it.
978
958
return True
979
959
980
960
@@ -1423,6 +1403,17 @@ def _do_waitpid(self, loop, expected_pid, callback, args):
1423
1403
1424
1404
self ._threads .pop (expected_pid )
1425
1405
1406
+ def can_use_pidfd ():
1407
+ if not hasattr (os , 'pidfd_open' ):
1408
+ return False
1409
+ try :
1410
+ pid = os .getpid ()
1411
+ os .close (os .pidfd_open (pid , 0 ))
1412
+ except OSError :
1413
+ # blocked by security policy like SECCOMP
1414
+ return False
1415
+ return True
1416
+
1426
1417
1427
1418
class _UnixDefaultEventLoopPolicy (events .BaseDefaultEventLoopPolicy ):
1428
1419
"""UNIX event loop policy with a watcher for child processes."""
@@ -1435,7 +1426,10 @@ def __init__(self):
1435
1426
def _init_watcher (self ):
1436
1427
with events ._lock :
1437
1428
if self ._watcher is None : # pragma: no branch
1438
- self ._watcher = ThreadedChildWatcher ()
1429
+ if can_use_pidfd ():
1430
+ self ._watcher = PidfdChildWatcher ()
1431
+ else :
1432
+ self ._watcher = ThreadedChildWatcher ()
1439
1433
if threading .current_thread () is threading .main_thread ():
1440
1434
self ._watcher .attach_loop (self ._local ._loop )
1441
1435
0 commit comments