Skip to content
Closed
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 Lib/test/libregrtest/runtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ def _runtest_inner2(ns, test_name):
if test_runner is None:
test_runner = functools.partial(_test_module, the_module)

pid = os.getpid()
nchild_before = support.get_child_processes(pid)

try:
if ns.huntrleaks:
# Return True if the test leaked references
Expand All @@ -249,6 +252,16 @@ def _runtest_inner2(ns, test_name):
gc.garbage.clear()

support.reap_children()
if nchild_before is not None:
nchild_after = support.get_child_processes(pid)
diff = len(nchild_after) - len(nchild_before)
if diff:
print(f"Warning -- {test_name} leaked "
f"{diff} child processes: "
f"created={nchild_after - nchild_before}, "
f"completed={nchild_before - nchild_after}",
file=sys.stderr)
support.environment_altered = True

return refleak

Expand Down
35 changes: 35 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3403,3 +3403,38 @@ def __exit__(self, *exc_info):
del self.exc_value
del self.exc_traceback
del self.thread


def get_child_processes(ppid):
"""
Get directly child processes of parent process identifier 'pid'.
"""
proc_dir = '/proc'
try:
names = os.listdir(proc_dir)
except FileNotFoundError:
return None

children = []
for name in names:
if not name.isdigit():
continue
pid = int(name)

filename = os.path.join(proc_dir, str(pid), 'status')
try:
fp = open(filename, encoding="utf-8")
except FileNotFoundError:
# process completed: ignore it
continue

proc_ppid = None
with fp:
for line in fp:
if line.startswith('PPid:'):
proc_ppid = int(line[5:].strip())
break
if proc_ppid == ppid:
children.append(pid)

return set(children)