Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Unified Diff: build/android/pylib/utils/reraiser_thread.py

Issue 2101243005: Add a snapshot of flutter/engine/src/build to our sdk (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: add README.dart Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « build/android/pylib/utils/repo_utils.py ('k') | build/android/pylib/utils/reraiser_thread_unittest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: build/android/pylib/utils/reraiser_thread.py
diff --git a/build/android/pylib/utils/reraiser_thread.py b/build/android/pylib/utils/reraiser_thread.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ec16b1908c85c61e5b66d5895373bb7d2fe67b3
--- /dev/null
+++ b/build/android/pylib/utils/reraiser_thread.py
@@ -0,0 +1,158 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Thread and ThreadGroup that reraise exceptions on the main thread."""
+# pylint: disable=W0212
+
+import logging
+import sys
+import threading
+import traceback
+
+from pylib.utils import watchdog_timer
+
+
+class TimeoutError(Exception):
+ """Module-specific timeout exception."""
+ pass
+
+
+def LogThreadStack(thread):
+ """Log the stack for the given thread.
+
+ Args:
+ thread: a threading.Thread instance.
+ """
+ stack = sys._current_frames()[thread.ident]
+ logging.critical('*' * 80)
+ logging.critical('Stack dump for thread %r', thread.name)
+ logging.critical('*' * 80)
+ for filename, lineno, name, line in traceback.extract_stack(stack):
+ logging.critical('File: "%s", line %d, in %s', filename, lineno, name)
+ if line:
+ logging.critical(' %s', line.strip())
+ logging.critical('*' * 80)
+
+
+class ReraiserThread(threading.Thread):
+ """Thread class that can reraise exceptions."""
+
+ def __init__(self, func, args=None, kwargs=None, name=None):
+ """Initialize thread.
+
+ Args:
+ func: callable to call on a new thread.
+ args: list of positional arguments for callable, defaults to empty.
+ kwargs: dictionary of keyword arguments for callable, defaults to empty.
+ name: thread name, defaults to Thread-N.
+ """
+ super(ReraiserThread, self).__init__(name=name)
+ if not args:
+ args = []
+ if not kwargs:
+ kwargs = {}
+ self.daemon = True
+ self._func = func
+ self._args = args
+ self._kwargs = kwargs
+ self._ret = None
+ self._exc_info = None
+
+ def ReraiseIfException(self):
+ """Reraise exception if an exception was raised in the thread."""
+ if self._exc_info:
+ raise self._exc_info[0], self._exc_info[1], self._exc_info[2]
+
+ def GetReturnValue(self):
+ """Reraise exception if present, otherwise get the return value."""
+ self.ReraiseIfException()
+ return self._ret
+
+ #override
+ def run(self):
+ """Overrides Thread.run() to add support for reraising exceptions."""
+ try:
+ self._ret = self._func(*self._args, **self._kwargs)
+ except: # pylint: disable=W0702
+ self._exc_info = sys.exc_info()
+
+
+class ReraiserThreadGroup(object):
+ """A group of ReraiserThread objects."""
+
+ def __init__(self, threads=None):
+ """Initialize thread group.
+
+ Args:
+ threads: a list of ReraiserThread objects; defaults to empty.
+ """
+ if not threads:
+ threads = []
+ self._threads = threads
+
+ def Add(self, thread):
+ """Add a thread to the group.
+
+ Args:
+ thread: a ReraiserThread object.
+ """
+ self._threads.append(thread)
+
+ def StartAll(self):
+ """Start all threads."""
+ for thread in self._threads:
+ thread.start()
+
+ def _JoinAll(self, watcher=None):
+ """Join all threads without stack dumps.
+
+ Reraises exceptions raised by the child threads and supports breaking
+ immediately on exceptions raised on the main thread.
+
+ Args:
+ watcher: Watchdog object providing timeout, by default waits forever.
+ """
+ if watcher is None:
+ watcher = watchdog_timer.WatchdogTimer(None)
+ alive_threads = self._threads[:]
+ while alive_threads:
+ for thread in alive_threads[:]:
+ if watcher.IsTimedOut():
+ raise TimeoutError('Timed out waiting for %d of %d threads.' %
+ (len(alive_threads), len(self._threads)))
+ # Allow the main thread to periodically check for interrupts.
+ thread.join(0.1)
+ if not thread.isAlive():
+ alive_threads.remove(thread)
+ # All threads are allowed to complete before reraising exceptions.
+ for thread in self._threads:
+ thread.ReraiseIfException()
+
+ def JoinAll(self, watcher=None):
+ """Join all threads.
+
+ Reraises exceptions raised by the child threads and supports breaking
+ immediately on exceptions raised on the main thread. Unfinished threads'
+ stacks will be logged on watchdog timeout.
+
+ Args:
+ watcher: Watchdog object providing timeout, by default waits forever.
+ """
+ try:
+ self._JoinAll(watcher)
+ except TimeoutError:
+ for thread in (t for t in self._threads if t.isAlive()):
+ LogThreadStack(thread)
+ raise
+
+ def GetAllReturnValues(self, watcher=None):
+ """Get all return values, joining all threads if necessary.
+
+ Args:
+ watcher: same as in |JoinAll|. Only used if threads are alive.
+ """
+ if any([t.isAlive() for t in self._threads]):
+ self.JoinAll(watcher)
+ return [t.GetReturnValue() for t in self._threads]
+
« no previous file with comments | « build/android/pylib/utils/repo_utils.py ('k') | build/android/pylib/utils/reraiser_thread_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698