Chromium Code Reviews| Index: gclient_utils.py |
| diff --git a/gclient_utils.py b/gclient_utils.py |
| index 794fc023bb21ed1c59797be895424461bb787c4d..556018105cc8cd0c30e42f0ec6e235efbe900eeb 100644 |
| --- a/gclient_utils.py |
| +++ b/gclient_utils.py |
| @@ -466,13 +466,15 @@ class _KillTimer(object): |
| # TODO(tandrii): we really want to make use of subprocess42 here, and not |
| # re-invent the wheel, but it's too much work :( |
| - def __init__(self, timeout, child): |
| + def __init__(self, timeout, child, child_info): |
| self._timeout = timeout |
| self._child = child |
| + self._child_info = child_info |
| self._cv = threading.Condition() |
| # All items below are protected by condition above. |
| self._kill_at = None |
| + self._killing_attempted = False |
| self._working = True |
| self._thread = None |
| @@ -483,6 +485,10 @@ class _KillTimer(object): |
| self._thread.daemon = True |
| self._thread.start() |
| + @property |
| + def killing_attempted(self): |
| + return self._killing_attempted |
| + |
| def poke(self): |
| if not self._timeout: |
| return |
| @@ -506,8 +512,9 @@ class _KillTimer(object): |
| self._cv.wait(timeout=left) |
| continue |
| try: |
| - logging.warn('killing child %s because of no output for %fs', |
| - self._child, self._timeout) |
| + logging.warn('killing child %s %s because of no output for %fs', |
| + self._child.pid, self._child_info, self._timeout) |
| + self._killing_attempted = True |
| self._child.kill() |
| except OSError: |
| logging.exception('failed to kill child %s', self._child) |
| @@ -528,9 +535,8 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None, |
| retry: If the process exits non-zero, sleep for a brief interval and try |
| again, up to RETRY_MAX times. |
| kill_timeout: (float) if given, number of seconds after which process would |
| - be killed if there is no output. Must not be used with shell=True as |
| - only shell process would be killed, but not processes spawned by |
| - shell. |
| + be killed. Must not be used with shell=True as only shell process |
| + would be killed, but not processes spawned by shell. |
| stderr is always redirected to stdout. |
| """ |
| @@ -543,6 +549,8 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None, |
| sleep_interval = RETRY_INITIAL_SLEEP |
| run_cwd = kwargs.get('cwd', os.getcwd()) |
| + debug_kid_info = "'%s' in %s" % (' '.join('"%s"' % x for x in args), run_cwd) |
|
Michael Achenbach
2016/08/30 15:02:52
Wouldn't str(args) be sufficient?
Never mind. Saw
|
| + |
| for _ in xrange(RETRY_MAX + 1): |
| kid = subprocess2.Popen( |
| args, bufsize=0, stdout=subprocess2.PIPE, stderr=subprocess2.STDOUT, |
| @@ -558,14 +566,13 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None, |
| # normally buffering is done for each line, but if svn requests input, no |
| # end-of-line character is output after the prompt and it would not show up. |
| try: |
| - timeout_killer = _KillTimer(kill_timeout, kid) |
| + timeout_killer = _KillTimer(kill_timeout, kid, debug_kid_info) |
|
Michael Achenbach
2016/08/30 15:02:52
naming nit: child vs. kid - well, it's from the ol
|
| in_byte = kid.stdout.read(1) |
| if in_byte: |
| if call_filter_on_first_line: |
| filter_fn(None) |
| in_line = '' |
| while in_byte: |
| - timeout_killer.poke() |
| output.write(in_byte) |
| if print_stdout: |
| stdout.write(in_byte) |
| @@ -594,8 +601,12 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None, |
| return output.getvalue() |
| if not retry: |
| break |
| - print ("WARNING: subprocess '%s' in %s failed; will retry after a short " |
| - 'nap...' % (' '.join('"%s"' % x for x in args), run_cwd)) |
| + print ("WARNING: subprocess %s failed; will retry after a short nap..." % |
| + debug_kid_info) |
| + if timeout_killer.killing_attempted: |
| + print('The subprocess above was likely killed because it looked hung. ' |
| + 'Output thus far:\n> %s' % |
| + ('\n> '.join(output.getvalue().splitlines()))) |
| time.sleep(sleep_interval) |
| sleep_interval *= 2 |
| raise subprocess2.CalledProcessError( |