Add an exception-trapping thread class
authorThomas Thrainer <thomasth@google.com>
Wed, 16 Apr 2014 15:07:09 +0000 (17:07 +0200)
committerThomas Thrainer <thomasth@google.com>
Thu, 17 Apr 2014 07:12:47 +0000 (09:12 +0200)
To have better control over threads, this patch adds a helper Thread
subclass which captures any exceptions occurring for later use.

Signed-off-by: Hrvoje Ribicic <riba@google.com>
Reviewed-by: Petr Pudlak <pudlak@google.com>
Signed-off-by: Thomas Thrainer <thomasth@google.com>
Reviewed-by: Helga Velroyen <helgav@google.com>

(cherry picked from commit e677d5e8e1c0ea7ef24e78f9ae842c9371449a77)

qa/qa_job_utils.py

index 5f3fbf4..22e8743 100644 (file)
@@ -24,6 +24,7 @@
 """
 
 import re
+import sys
 import threading
 import time
 
@@ -220,6 +221,40 @@ def _GetBlockingLocks():
   return blocking_locks
 
 
+class QAThread(threading.Thread):
+  """ An exception-preserving thread that executes a given function.
+
+  """
+  def __init__(self, fn, args, kwargs):
+    """ Constructor accepting the function to be invoked later.
+
+    """
+    threading.Thread.__init__(self)
+    self._fn = fn
+    self._args = args
+    self._kwargs = kwargs
+    self._exc_info = None
+
+  def run(self):
+    """ Executes the function, preserving exception info if necessary.
+
+    """
+    # pylint: disable=W0702
+    # We explicitly want to catch absolutely anything
+    try:
+      self._fn(*self._args, **self._kwargs)
+    except:
+      self._exc_info = sys.exc_info()
+    # pylint: enable=W0702
+
+  def reraise(self):
+    """ Reraises any exceptions that might have occured during thread execution.
+
+    """
+    if self._exc_info is not None:
+      raise self._exc_info[0], self._exc_info[1], self._exc_info[2]
+
+
 # TODO: Can this be done as a decorator? Implement as needed.
 def RunWithLocks(fn, locks, timeout, block, *args, **kwargs):
   """ Runs the given function, acquiring a set of locks beforehand.