@@ -126,6 +126,38 @@ def __repr__(self):
126126 info .append (f'pid={ popen .pid } ' )
127127 return '<%s>' % ' ' .join (info )
128128
129+ def _kill (self ):
130+ dt = time .monotonic () - self .start_time
131+
132+ popen = self ._popen
133+ pid = popen .pid
134+ print ("Kill worker process %s running for %.1f sec" % (pid , dt ),
135+ file = sys .stderr , flush = True )
136+
137+ try :
138+ popen .kill ()
139+ return True
140+ except OSError as exc :
141+ print ("WARNING: Failed to kill worker process %s: %r" % (pid , exc ),
142+ file = sys .stderr , flush = True )
143+ return False
144+
145+ def _close_wait (self ):
146+ popen = self ._popen
147+
148+ # stdout and stderr must be closed to ensure that communicate()
149+ # does not hang
150+ popen .stdout .close ()
151+ popen .stderr .close ()
152+
153+ try :
154+ popen .wait (JOIN_TIMEOUT )
155+ except (subprocess .TimeoutExpired , OSError ) as exc :
156+ print ("WARNING: Failed to wait for worker process %s "
157+ "completion (timeout=%.1f sec): %r"
158+ % (popen .pid , JOIN_TIMEOUT , exc ),
159+ file = sys .stderr , flush = True )
160+
129161 def kill (self ):
130162 """
131163 Kill the current process (if any).
@@ -135,30 +167,45 @@ def kill(self):
135167 """
136168 self ._killed = True
137169
138- popen = self ._popen
139- if popen is None :
170+ if self ._popen is None :
140171 return
141- popen .kill ()
142- # stdout and stderr must be closed to ensure that communicate()
143- # does not hang
144- popen .stdout .close ()
145- popen .stderr .close ()
146- popen .wait ()
172+
173+ if not self ._kill ():
174+ return
175+
176+ self ._close_wait ()
147177
148178 def mp_result_error (self , test_name , error_type , stdout = '' , stderr = '' ,
149179 err_msg = None ):
150180 test_time = time .monotonic () - self .start_time
151181 result = TestResult (test_name , error_type , test_time , None )
152182 return MultiprocessResult (result , stdout , stderr , err_msg )
153183
184+ def _timedout (self , test_name ):
185+ self ._kill ()
186+
187+ stdout = sterr = ''
188+ popen = self ._popen
189+ try :
190+ stdout , stderr = popen .communicate (timeout = JOIN_TIMEOUT )
191+ except (subprocess .TimeoutExpired , OSError ) as exc :
192+ print ("WARNING: Failed to read worker process %s output "
193+ "(timeout=%.1f sec): %r"
194+ % (popen .pid , exc , timeout ),
195+ file = sys .stderr , flush = True )
196+
197+ self ._close_wait ()
198+
199+ return self .mp_result_error (test_name , TIMEOUT , stdout , stderr )
200+
154201 def _runtest (self , test_name ):
155202 try :
156203 self .start_time = time .monotonic ()
157204 self .current_test_name = test_name
158205
159206 self ._popen = run_test_in_subprocess (test_name , self .ns )
160207 popen = self ._popen
161- with popen :
208+ try :
162209 try :
163210 if self ._killed :
164211 # If kill() has been called before self._popen is set,
@@ -175,12 +222,7 @@ def _runtest(self, test_name):
175222 # on reading closed stdout/stderr
176223 raise ExitThread
177224
178- popen .kill ()
179- stdout , stderr = popen .communicate ()
180- self .kill ()
181-
182- return self .mp_result_error (test_name , TIMEOUT ,
183- stdout , stderr )
225+ return self ._timedout (test_name )
184226 except OSError :
185227 if self ._killed :
186228 # kill() has been called: communicate() fails
@@ -190,8 +232,10 @@ def _runtest(self, test_name):
190232 except :
191233 self .kill ()
192234 raise
235+ finally :
236+ self ._close_wait ()
193237
194- retcode = popen .wait ()
238+ retcode = popen .returncode
195239 finally :
196240 self .current_test_name = None
197241 self ._popen = None
@@ -286,10 +330,11 @@ def wait_workers(self):
286330 if not worker .is_alive ():
287331 break
288332 dt = time .monotonic () - start_time
289- print ("Wait for regrtest worker %r for %.1f sec" % (worker , dt ))
333+ print ("Wait for regrtest worker %r for %.1f sec" % (worker , dt ),
334+ flush = True )
290335 if dt > JOIN_TIMEOUT :
291336 print ("Warning -- failed to join a regrtest worker %s"
292- % worker )
337+ % worker , flush = True )
293338 break
294339
295340 def _get_result (self ):
0 commit comments