[3.8] bpo-37531: Enhance regrtest multiprocess timeout (GH-15345) by vstinner · Pull Request #15871 · python/cpython
def _kill(self): dt = time.monotonic() - self.start_time
popen = self._popen pid = popen.pid print("Kill worker process %s running for %.1f sec" % (pid, dt), file=sys.stderr, flush=True)
try: popen.kill() return True except OSError as exc: print("WARNING: Failed to kill worker process %s: %r" % (pid, exc), file=sys.stderr, flush=True) return False
def _close_wait(self): popen = self._popen
# stdout and stderr must be closed to ensure that communicate() # does not hang popen.stdout.close() popen.stderr.close()
try: popen.wait(JOIN_TIMEOUT) except (subprocess.TimeoutExpired, OSError) as exc: print("WARNING: Failed to wait for worker process %s " "completion (timeout=%.1f sec): %r" % (popen.pid, JOIN_TIMEOUT, exc), file=sys.stderr, flush=True)
def kill(self): """ Kill the current process (if any).
popen = self._popen if popen is None: if self._popen is None: return popen.kill() # stdout and stderr must be closed to ensure that communicate() # does not hang popen.stdout.close() popen.stderr.close() popen.wait()
if not self._kill(): return
self._close_wait()
def mp_result_error(self, test_name, error_type, stdout='', stderr='', err_msg=None): test_time = time.monotonic() - self.start_time result = TestResult(test_name, error_type, test_time, None) return MultiprocessResult(result, stdout, stderr, err_msg)
def _timedout(self, test_name): self._kill()
stdout = sterr = '' popen = self._popen try: stdout, stderr = popen.communicate(timeout=JOIN_TIMEOUT) except (subprocess.TimeoutExpired, OSError) as exc: print("WARNING: Failed to read worker process %s output " "(timeout=%.1f sec): %r" % (popen.pid, exc, timeout), file=sys.stderr, flush=True)
self._close_wait()
return self.mp_result_error(test_name, TIMEOUT, stdout, stderr)
def _runtest(self, test_name): try: self.start_time = time.monotonic() self.current_test_name = test_name
self._popen = run_test_in_subprocess(test_name, self.ns) popen = self._popen with popen: try: try: if self._killed: # If kill() has been called before self._popen is set,
popen.kill() stdout, stderr = popen.communicate() self.kill()
return self.mp_result_error(test_name, TIMEOUT, stdout, stderr) return self._timedout(test_name) except OSError: if self._killed: # kill() has been called: communicate() fails
retcode = popen.wait() retcode = popen.returncode finally: self.current_test_name = None self._popen = None
def _get_result(self):