| Index: build/android/pylib/utils/timeout_retry.py
|
| diff --git a/build/android/pylib/utils/timeout_retry.py b/build/android/pylib/utils/timeout_retry.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cdd8b9a593bf5943f748b259b44b4dd3ba267806
|
| --- /dev/null
|
| +++ b/build/android/pylib/utils/timeout_retry.py
|
| @@ -0,0 +1,45 @@
|
| +# 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.
|
| +
|
| +"""A utility to run functions with timeouts and retries."""
|
| +
|
| +import functools
|
| +import threading
|
| +
|
| +import reraiser_thread
|
| +import watchdog_timer
|
| +
|
| +
|
| +def Run(func, timeout, retries, args=[], kwargs={}):
|
| + """Runs the passed function in a separate thread with timeouts and retries.
|
| +
|
| + Args:
|
| + func: the function to be wrapped.
|
| + timeout: the timeout in seconds for each try.
|
| + retries: the number of retries.
|
| + args: list of positional args to pass to |func|.
|
| + kwargs: dictionary of keyword args to pass to |func|.
|
| +
|
| + Returns:
|
| + The return value of func(*args, **kwargs).
|
| + """
|
| + # The return value uses a list because Python variables are references, not
|
| + # values. Closures make a copy of the reference, so updating the closure's
|
| + # reference wouldn't update where the original reference pointed.
|
| + ret = [None]
|
| + def RunOnTimeoutThread():
|
| + ret[0] = func(*args, **kwargs)
|
| +
|
| + while True:
|
| + try:
|
| + name = 'TimeoutThread-for-%s' % threading.current_thread().name
|
| + thread_group = reraiser_thread.ReraiserThreadGroup(
|
| + [reraiser_thread.ReraiserThread(RunOnTimeoutThread, name=name)])
|
| + thread_group.StartAll()
|
| + thread_group.JoinAll(watchdog_timer.WatchdogTimer(timeout))
|
| + return ret[0]
|
| + except:
|
| + if retries <= 0:
|
| + raise
|
| + retries -= 1
|
|
|