@@ -28,6 +28,7 @@ import socket
2828import stat
2929import subprocess
3030import sys
31+ import threading
3132import time
3233import urllib .error
3334import urllib .request
@@ -121,6 +122,17 @@ def print_line(prefix, m):
121122 sys .stdout .buffer .flush ()
122123
123124
125+ def reap_zombies (main_subprocess ):
126+ """Wait for main_subprocess to exit, while awaiting any other child processes"""
127+ while main_subprocess .poll () is None :
128+ with main_subprocess ._waitpid_lock :
129+ if main_subprocess .returncode is not None :
130+ return
131+ pid , status = os .wait ()
132+ if pid == main_subprocess .pid :
133+ main_subprocess ._handle_exitstatus (status )
134+
135+
124136def _call_windows_retry (func , args = (), retry_max = 5 , retry_delay = 0.5 ):
125137 """
126138 It's possible to see spurious errors on Windows due to various things
@@ -278,6 +290,13 @@ def run_command(prefix, args, *, extra_env=None, cwd=None):
278290
279291 stdout = io .TextIOWrapper (p .stdout , encoding = "latin1" )
280292
293+ if os .getpid () == 1 :
294+ # in docker we're init, so we get to adopt unawaited zombies
295+ reaper_thread = threading .Thread (target = reap_zombies , args = (p ,))
296+ reaper_thread .start ()
297+ else :
298+ reaper_thread = None
299+
281300 while True :
282301 data = stdout .readline ().encode ("latin1" )
283302
@@ -286,6 +305,8 @@ def run_command(prefix, args, *, extra_env=None, cwd=None):
286305
287306 print_line (prefix , data )
288307
308+ if reaper_thread :
309+ reaper_thread .join ()
289310 return p .wait ()
290311
291312
0 commit comments