Home | History | Annotate | Download | only in utils
      1 # Copyright 2013 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """A utility to run functions with timeouts and retries."""
      6 
      7 import functools
      8 import threading
      9 
     10 import reraiser_thread
     11 import watchdog_timer
     12 
     13 
     14 def Run(func, timeout, retries, args=[], kwargs={}):
     15   """Runs the passed function in a separate thread with timeouts and retries.
     16 
     17   Args:
     18     func: the function to be wrapped.
     19     timeout: the timeout in seconds for each try.
     20     retries: the number of retries.
     21     args: list of positional args to pass to |func|.
     22     kwargs: dictionary of keyword args to pass to |func|.
     23 
     24   Returns:
     25     The return value of func(*args, **kwargs).
     26   """
     27   # The return value uses a list because Python variables are references, not
     28   # values. Closures make a copy of the reference, so updating the closure's
     29   # reference wouldn't update where the original reference pointed.
     30   ret = [None]
     31   def RunOnTimeoutThread():
     32     ret[0] = func(*args, **kwargs)
     33 
     34   while True:
     35     try:
     36       name = 'TimeoutThread-for-%s' % threading.current_thread().name
     37       thread_group = reraiser_thread.ReraiserThreadGroup(
     38           [reraiser_thread.ReraiserThread(RunOnTimeoutThread, name=name)])
     39       thread_group.StartAll()
     40       thread_group.JoinAll(watchdog_timer.WatchdogTimer(timeout))
     41       return ret[0]
     42     except:
     43       if retries <= 0:
     44         raise
     45       retries -= 1
     46