| Index: gclient_utils.py
|
| diff --git a/gclient_utils.py b/gclient_utils.py
|
| index 041813b0d164322a816669b175e3f7259ac109cb..bf9803e86f3552c151d788cec8cf354233dc432a 100644
|
| --- a/gclient_utils.py
|
| +++ b/gclient_utils.py
|
| @@ -323,6 +323,56 @@ def MakeFileAnnotated(fileobj, include_zero=False):
|
| return Annotated(fileobj)
|
|
|
|
|
| +GCLIENT_CHILDREN = []
|
| +GCLIENT_CHILDREN_LOCK = threading.Lock()
|
| +
|
| +
|
| +class GClientChildren(object):
|
| + @staticmethod
|
| + def add(popen_obj):
|
| + with GCLIENT_CHILDREN_LOCK:
|
| + GCLIENT_CHILDREN.append(popen_obj)
|
| +
|
| + @staticmethod
|
| + def remove(popen_obj):
|
| + with GCLIENT_CHILDREN_LOCK:
|
| + GCLIENT_CHILDREN.remove(popen_obj)
|
| +
|
| + @staticmethod
|
| + def _attemptToKillChildren():
|
| + global GCLIENT_CHILDREN
|
| + with GCLIENT_CHILDREN_LOCK:
|
| + zombies = [c for c in GCLIENT_CHILDREN if c.poll() is None]
|
| +
|
| + for zombie in zombies:
|
| + try:
|
| + zombie.kill()
|
| + except OSError:
|
| + pass
|
| +
|
| + with GCLIENT_CHILDREN_LOCK:
|
| + GCLIENT_CHILDREN = [k for k in GCLIENT_CHILDREN if k.poll() is not None]
|
| +
|
| + @staticmethod
|
| + def _areZombies():
|
| + with GCLIENT_CHILDREN_LOCK:
|
| + return bool(GCLIENT_CHILDREN)
|
| +
|
| + @staticmethod
|
| + def KillAllRemainingChildren():
|
| + GClientChildren._attemptToKillChildren()
|
| +
|
| + if GClientChildren._areZombies():
|
| + time.sleep(0.5)
|
| + GClientChildren._attemptToKillChildren()
|
| +
|
| + with GCLIENT_CHILDREN_LOCK:
|
| + if GCLIENT_CHILDREN:
|
| + print >> sys.stderr, 'Could not kill the following subprocesses:'
|
| + for zombie in GCLIENT_CHILDREN:
|
| + print >> sys.stderr, ' ', zombie.pid
|
| +
|
| +
|
| def CheckCallAndFilter(args, stdout=None, filter_fn=None,
|
| print_stdout=None, call_filter_on_first_line=False,
|
| **kwargs):
|
| @@ -344,6 +394,8 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None,
|
| args, bufsize=0, stdout=subprocess2.PIPE, stderr=subprocess2.STDOUT,
|
| **kwargs)
|
|
|
| + GClientChildren.add(kid)
|
| +
|
| # Do a flush of stdout before we begin reading from the subprocess2's stdout
|
| stdout.flush()
|
|
|
| @@ -375,6 +427,11 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None,
|
| if len(in_line):
|
| filter_fn(in_line)
|
| rv = kid.wait()
|
| +
|
| + # Don't put this in a 'finally,' since the child may still run if we get an
|
| + # exception.
|
| + GClientChildren.remove(kid)
|
| +
|
| except KeyboardInterrupt:
|
| print >> sys.stderr, 'Failed while running "%s"' % ' '.join(args)
|
| raise
|
| @@ -657,6 +714,7 @@ class ExecutionQueue(object):
|
| self.index = index
|
| self.args = args
|
| self.kwargs = kwargs
|
| + self.daemon = True
|
|
|
| def run(self):
|
| """Runs in its own thread."""
|
| @@ -664,18 +722,23 @@ class ExecutionQueue(object):
|
| work_queue = self.kwargs['work_queue']
|
| try:
|
| self.item.run(*self.args, **self.kwargs)
|
| + except KeyboardInterrupt:
|
| + logging.info('Caught KeyboardInterrupt in thread %s' % self.item.name)
|
| + logging.info(str(sys.exc_info()))
|
| + work_queue.exceptions.put(sys.exc_info())
|
| + raise
|
| except Exception:
|
| # Catch exception location.
|
| logging.info('Caught exception in thread %s' % self.item.name)
|
| logging.info(str(sys.exc_info()))
|
| work_queue.exceptions.put(sys.exc_info())
|
| - logging.info('_Worker.run(%s) done' % self.item.name)
|
| -
|
| - work_queue.ready_cond.acquire()
|
| - try:
|
| - work_queue.ready_cond.notifyAll()
|
| finally:
|
| - work_queue.ready_cond.release()
|
| + logging.info('_Worker.run(%s) done' % self.item.name)
|
| + work_queue.ready_cond.acquire()
|
| + try:
|
| + work_queue.ready_cond.notifyAll()
|
| + finally:
|
| + work_queue.ready_cond.release()
|
|
|
|
|
| def GetEditor(git, git_editor=None):
|
|
|