]> granicus.if.org Git - python/commitdiff
[3.6] bpo-31160: Backport reap_children() fixes from master to 3.6 (#3060)
authorVictor Stinner <victor.stinner@gmail.com>
Thu, 10 Aug 2017 14:02:00 +0000 (16:02 +0200)
committerGitHub <noreply@github.com>
Thu, 10 Aug 2017 14:02:00 +0000 (16:02 +0200)
* bpo-31160: Fix test_builtin for zombie process (#3043)

PtyTests.run_child() now calls os.waitpid() to read the exit status
of the child process to avoid creating zombie process and leaking
processes in the background.
(cherry picked from commit 4baca1b0f7325032598cd38e7ceffc79b616d255)

* bpo-31160: regrtest now reaps child processes (#3044)

Add a post_test_cleanup() function which currently only calls
support.reap_children().
(cherry picked from commit e3510d74aacc477c30f42f2b941d69689bbc478e)

* bpo-31160: test_builtin: don't check waitpid() status (#3050)

(cherry picked from commit 3ca9f50f96cfa5c1b7aa56639042531b57f07fbb)

* bpo-31160: test_tempfile: Fix reap_children() warning (#3056)

TestRandomNameSequence.test_process_awareness() now calls
os.waitpid() to avoid leaking a zombie process.
(cherry picked from commit 6c8c2943d996b59a48d331f61f22cbe72933910e)

Lib/test/libregrtest/runtest.py
Lib/test/test_builtin.py
Lib/test/test_tempfile.py

index fda4ca1ebca094fda48280963d7324b5db35b058..d716b83e23547260f56b72a4aefe19df2af11aee 100644 (file)
@@ -143,6 +143,10 @@ def runtest(ns, test):
 runtest.stringio = None
 
 
+def post_test_cleanup():
+    support.reap_children()
+
+
 def runtest_inner(ns, test, display_failure=True):
     support.unload(test)
 
@@ -170,6 +174,7 @@ def runtest_inner(ns, test, display_failure=True):
             if ns.huntrleaks:
                 refleak = dash_R(the_module, test, test_runner, ns.huntrleaks)
             test_time = time.time() - start_time
+        post_test_cleanup()
     except support.ResourceDenied as msg:
         if not ns.quiet and not ns.pgo:
             print(test, "skipped --", msg, flush=True)
index 7a4b7eb9176ab93251cdbab91b34329c12f60e41..49c4a53c052dc211b95d15977fc04ff650bbbff7 100644 (file)
@@ -1560,6 +1560,10 @@ class PtyTests(unittest.TestCase):
             self.fail("got %d lines in pipe but expected 2, child output was:\n%s"
                       % (len(lines), child_output))
         os.close(fd)
+
+        # Wait until the child process completes
+        os.waitpid(pid, 0)
+
         return lines
 
     def check_input_tty(self, prompt, terminal_input, stdio_encoding=None):
index d0cf04b0cb67ca5bac7887cd9cdef0c019c60f20..710756bde64c04fd2758e38c545043e2e2726e8a 100644 (file)
@@ -78,7 +78,6 @@ class BaseTestCase(unittest.TestCase):
     def tearDown(self):
         self._warnings_manager.__exit__(None, None, None)
 
-
     def nameCheck(self, name, dir, pre, suf):
         (ndir, nbase) = os.path.split(name)
         npre  = nbase[:len(pre)]
@@ -184,12 +183,15 @@ class TestRandomNameSequence(BaseTestCase):
         try:
             pid = os.fork()
             if not pid:
+                # child process
                 os.close(read_fd)
                 os.write(write_fd, next(self.r).encode("ascii"))
                 os.close(write_fd)
                 # bypass the normal exit handlers- leave those to
                 # the parent.
                 os._exit(0)
+
+            # parent process
             parent_value = next(self.r)
             child_value = os.read(read_fd, len(parent_value)).decode("ascii")
         finally:
@@ -200,6 +202,10 @@ class TestRandomNameSequence(BaseTestCase):
                     os.kill(pid, signal.SIGKILL)
                 except OSError:
                     pass
+
+                # Read the process exit status to avoid zombie process
+                os.waitpid(pid, 0)
+
             os.close(read_fd)
             os.close(write_fd)
         self.assertNotEqual(child_value, parent_value)