Chromium Code Reviews| Index: gclient_utils.py |
| diff --git a/gclient_utils.py b/gclient_utils.py |
| index 041813b0d164322a816669b175e3f7259ac109cb..eb964042ff156c1b2890feda4590642bb723a45d 100644 |
| --- a/gclient_utils.py |
| +++ b/gclient_utils.py |
| @@ -323,6 +323,58 @@ def MakeFileAnnotated(fileobj, include_zero=False): |
| return Annotated(fileobj) |
| +GCLIENT_CHILDREN = [] |
|
Isaac (away)
2013/05/03 22:00:38
I think set() would be a better data structure.
|
| +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: |
| + if GCLIENT_CHILDREN: |
|
M-A Ruel
2013/05/03 21:26:42
return bool(GCLIENT_CHILDREN)
Isaac (away)
2013/05/03 22:00:38
Should this filter based on k.poll()?
|
| + return True |
| + return False |
| + |
| + @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 +396,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 +429,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 +716,7 @@ class ExecutionQueue(object): |
| self.index = index |
| self.args = args |
| self.kwargs = kwargs |
| + self.daemon = True |
|
Isaac (away)
2013/05/03 22:00:38
nice!
|
| def run(self): |
| """Runs in its own thread.""" |
| @@ -664,18 +724,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) |
|
Isaac (away)
2013/05/03 22:00:38
Use logger formatting, i.e.:
logging.info('Caught
|
| + 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) |
|
Isaac (away)
2013/05/03 22:00:38
ditto, don't format in logging strings.
|
| + work_queue.ready_cond.acquire() |
| + try: |
| + work_queue.ready_cond.notifyAll() |
| + finally: |
| + work_queue.ready_cond.release() |
| def GetEditor(git, git_editor=None): |