mirror of
https://github.com/python/cpython
synced 2024-09-21 17:49:17 +00:00
Enhance support.reap_children() (#3036)
* reap_children() now sets environment_altered to True to detect bugs using python3 -m test --fail-env-changed * Replace bare "except:" with "except OSError:" in reap_children() * Write an unit test for reap_children() using a timeout of 60 seconds
This commit is contained in:
parent
aa8ec34ad5
commit
b501147980
|
@ -2073,26 +2073,35 @@ def decorator(*args):
|
|||
threading_cleanup(*key)
|
||||
return decorator
|
||||
|
||||
|
||||
def reap_children():
|
||||
"""Use this function at the end of test_main() whenever sub-processes
|
||||
are started. This will help ensure that no extra children (zombies)
|
||||
stick around to hog resources and create problems when looking
|
||||
for refleaks.
|
||||
"""
|
||||
global environment_altered
|
||||
|
||||
# Need os.waitpid(-1, os.WNOHANG): Windows is not supported
|
||||
if not (hasattr(os, 'waitpid') and hasattr(os, 'WNOHANG')):
|
||||
return
|
||||
|
||||
# Reap all our dead child processes so we don't leave zombies around.
|
||||
# These hog resources and might be causing some of the buildbots to die.
|
||||
if hasattr(os, 'waitpid'):
|
||||
any_process = -1
|
||||
while True:
|
||||
try:
|
||||
# This will raise an exception on Windows. That's ok.
|
||||
pid, status = os.waitpid(any_process, os.WNOHANG)
|
||||
if pid == 0:
|
||||
break
|
||||
print("Warning -- reap_children() reaped child process %s"
|
||||
% pid, file=sys.stderr)
|
||||
except:
|
||||
break
|
||||
while True:
|
||||
try:
|
||||
# Read the exit status of any child process which already completed
|
||||
pid, status = os.waitpid(-1, os.WNOHANG)
|
||||
except OSError:
|
||||
break
|
||||
|
||||
if pid == 0:
|
||||
break
|
||||
|
||||
print("Warning -- reap_children() reaped child process %s"
|
||||
% pid, file=sys.stderr)
|
||||
environment_altered = True
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def start_threads(threads, unlock=None):
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import contextlib
|
||||
import errno
|
||||
import importlib
|
||||
import io
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import stat
|
||||
import sys
|
||||
import os
|
||||
import unittest
|
||||
import socket
|
||||
import tempfile
|
||||
import errno
|
||||
import time
|
||||
import unittest
|
||||
from test import support
|
||||
|
||||
TESTFN = support.TESTFN
|
||||
|
@ -378,6 +381,51 @@ def test_check__all__(self):
|
|||
|
||||
self.assertRaises(AssertionError, support.check__all__, self, unittest)
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'waitpid') and hasattr(os, 'WNOHANG'),
|
||||
'need os.waitpid() and os.WNOHANG')
|
||||
def test_reap_children(self):
|
||||
# Make sure that there is no other pending child process
|
||||
support.reap_children()
|
||||
|
||||
# Create a child process
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
# child process: do nothing, just exit
|
||||
os._exit(0)
|
||||
|
||||
t0 = time.monotonic()
|
||||
deadline = time.monotonic() + 60.0
|
||||
|
||||
was_altered = support.environment_altered
|
||||
try:
|
||||
support.environment_altered = False
|
||||
stderr = io.StringIO()
|
||||
|
||||
while True:
|
||||
if time.monotonic() > deadline:
|
||||
self.fail("timeout")
|
||||
|
||||
with contextlib.redirect_stderr(stderr):
|
||||
support.reap_children()
|
||||
|
||||
# Use environment_altered to check if reap_children() found
|
||||
# the child process
|
||||
if support.environment_altered:
|
||||
break
|
||||
|
||||
# loop until the child process completed
|
||||
time.sleep(0.100)
|
||||
|
||||
msg = "Warning -- reap_children() reaped child process %s" % pid
|
||||
self.assertIn(msg, stderr.getvalue())
|
||||
self.assertTrue(support.environment_altered)
|
||||
finally:
|
||||
support.environment_altered = was_altered
|
||||
|
||||
# Just in case, check again that there is no other
|
||||
# pending child process
|
||||
support.reap_children()
|
||||
|
||||
# XXX -follows a list of untested API
|
||||
# make_legacy_pyc
|
||||
# is_resource_enabled
|
||||
|
@ -398,7 +446,6 @@ def test_check__all__(self):
|
|||
# run_doctest
|
||||
# threading_cleanup
|
||||
# reap_threads
|
||||
# reap_children
|
||||
# strip_python_stderr
|
||||
# args_from_interpreter_flags
|
||||
# can_symlink
|
||||
|
|
Loading…
Reference in a new issue