Chromium Code Reviews| Index: gclient_utils.py |
| diff --git a/gclient_utils.py b/gclient_utils.py |
| index 041813b0d164322a816669b175e3f7259ac109cb..126b073c7048565f88ab2ff289f9500db4423314 100644 |
| --- a/gclient_utils.py |
| +++ b/gclient_utils.py |
| @@ -323,6 +323,61 @@ def MakeFileAnnotated(fileobj, include_zero=False): |
| return Annotated(fileobj) |
| +GCLIENT_CHILDREN = {} |
|
M-A Ruel
2013/05/03 20:54:12
Why a dict instead of a list?
Mike Stip (use stip instead)
2013/05/03 21:16:08
Since I figured it was better to delete via pid th
|
| +GCLIENT_CHILDREN_LOCK = threading.Lock() |
| + |
| + |
| +class GClientChildren(object): |
| + @staticmethod |
| + def add(popen_obj): |
| + with GCLIENT_CHILDREN_LOCK: |
| + GCLIENT_CHILDREN[popen_obj.pid] = popen_obj |
| + |
| + @staticmethod |
| + def remove(popen_obj): |
| + with GCLIENT_CHILDREN_LOCK: |
| + del GCLIENT_CHILDREN[popen_obj.pid] |
| + |
| + @staticmethod |
| + def _attemptToKillChildren(): |
| + dead_objs = [] |
| + |
| + with GCLIENT_CHILDREN_LOCK: |
| + for child in GCLIENT_CHILDREN.values(): |
|
M-A Ruel
2013/05/03 20:54:12
with GCLIENT_CHILDREN_LOCK:
zombies = [c for c i
Mike Stip (use stip instead)
2013/05/03 21:16:08
Done.
|
| + if child.poll(): |
| + dead_objs.append(child) |
| + continue |
| + |
| + try: |
| + child.kill() |
| + if child.poll(): |
| + dead_objs.append(child) |
| + except OSError: |
| + pass |
| + |
| + for obj in dead_objs: |
| + GClientChildren.remove(obj) |
| + |
| + @staticmethod |
| + def KillAllRemainingChildren(): |
| + GClientChildren._attemptToKillChildren() |
| + |
| + leftovers = False |
| + with GCLIENT_CHILDREN_LOCK: |
| + if GCLIENT_CHILDREN: |
| + leftovers = True |
| + |
| + if leftovers: |
| + time.sleep(0.5) |
| + GClientChildren._attemptToKillChildren() |
| + |
| + with GCLIENT_CHILDREN_LOCK: |
| + if GCLIENT_CHILDREN: |
| + print >> sys.stderr, 'Could not kill the folling subprocesses:' |
| + for pid in GCLIENT_CHILDREN: |
| + print >> sys.stderr, ' ', pid |
| + |
| + |
| def CheckCallAndFilter(args, stdout=None, filter_fn=None, |
| print_stdout=None, call_filter_on_first_line=False, |
| **kwargs): |
| @@ -344,6 +399,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 +432,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 +719,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 +727,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): |