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

Side by Side Diff: build/android/pylib/utils/timeout_retry.py

Issue 636273004: Make TimeoutRetryThread's stoppable (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: do not catch CommandFailedError in _WaitFor Created 6 years, 1 month 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 unified diff | Download patch
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """A utility to run functions with timeouts and retries.""" 5 """A utility to run functions with timeouts and retries."""
6 # pylint: disable=W0702 6 # pylint: disable=W0702
7 7
8 import threading 8 import threading
9 9
10 from pylib.utils import reraiser_thread 10 from pylib.utils import reraiser_thread
11 from pylib.utils import watchdog_timer 11 from pylib.utils import watchdog_timer
12 12
13 13
14 class TimeoutRetryThread(reraiser_thread.ReraiserThread): 14 class TimeoutRetryThread(reraiser_thread.ReraiserThread):
jbudorick 2014/10/30 02:27:03 This interface feels bloated. Why can't we just na
perezju 2014/10/30 18:44:45 Yeah ..., have a look at the new one. I hope it's
15 pass 15 def __init__(self, func, timeout, name):
16 super(TimeoutRetryThread, self).__init__(func, name=name)
17 self._watcher = watchdog_timer.WatchdogTimer(timeout)
18
19 def GetWatcher(self):
20 """Returns the watchdog timer keeping track of this thread's time."""
21 return self._watcher
22
23 def ElapsedTime(self):
24 """Returns the number of seconds elapsed since the thread started."""
25 return self._watcher.ElapsedTime()
26
27 def RemainingTime(self):
28 """Returns the number of seconds remaining until the thread times out.
29
30 Raises:
31 reraiser_thread.TimeoutError if there is no remaining time.
32 """
33 remaining = self._watcher.RemainingTime()
34 if remaining is not None and remaining <= 0:
35 self.RaiseTimeout()
36 return remaining
37
38 def CheckTimeout(self):
39 """Checks if thread should time out.
40
41 Raises:
42 reraiser_thread.TimeoutError if the thread has timed out.
43 """
44 if self._watcher.IsTimedOut():
45 self.RaiseTimeout()
46
47 def RaiseTimeout(self):
48 """Raises the thread time out error."""
49 reraiser_thread.LogThreadStack(self)
perezju 2014/10/29 18:16:50 Note, we need to log here because the thread is go
50 raise reraiser_thread.TimeoutError('%s timed out' % self.name)
51
52
53 def GetTimeoutThread():
jbudorick 2014/10/30 02:27:03 Nit: rename this, it sounds like it's creating a t
perezju 2014/10/30 18:44:45 Done.
54 """Get the current thread if it is a TimeoutRetryThread.
55
56 Returns:
57 The current thread if it is a TimeoutRetryThread, otherwise None.
58 """
59 current_thread = threading.current_thread()
60 if isinstance(current_thread, TimeoutRetryThread):
61 return current_thread
62 else:
63 return None
16 64
17 65
18 def Run(func, timeout, retries, args=None, kwargs=None): 66 def Run(func, timeout, retries, args=None, kwargs=None):
19 """Runs the passed function in a separate thread with timeouts and retries. 67 """Runs the passed function in a separate thread with timeouts and retries.
20 68
21 Args: 69 Args:
22 func: the function to be wrapped. 70 func: the function to be wrapped.
23 timeout: the timeout in seconds for each try. 71 timeout: the timeout in seconds for each try.
24 retries: the number of retries. 72 retries: the number of retries.
25 args: list of positional args to pass to |func|. 73 args: list of positional args to pass to |func|.
26 kwargs: dictionary of keyword args to pass to |func|. 74 kwargs: dictionary of keyword args to pass to |func|.
27 75
28 Returns: 76 Returns:
29 The return value of func(*args, **kwargs). 77 The return value of func(*args, **kwargs).
30 """ 78 """
31 if not args: 79 if not args:
32 args = [] 80 args = []
33 if not kwargs: 81 if not kwargs:
34 kwargs = {} 82 kwargs = {}
35 83
36 # The return value uses a list because Python variables are references, not 84 # The return value uses a list because Python variables are references, not
37 # values. Closures make a copy of the reference, so updating the closure's 85 # values. Closures make a copy of the reference, so updating the closure's
38 # reference wouldn't update where the original reference pointed. 86 # reference wouldn't update where the original reference pointed.
39 ret = [None] 87 ret = [None]
40 def RunOnTimeoutThread(): 88 def RunOnTimeoutThread():
41 ret[0] = func(*args, **kwargs) 89 ret[0] = func(*args, **kwargs)
42 90
91 num_try = 1
jbudorick 2014/10/30 02:27:03 I'm guessing you're trying to "correct" the retrie
perezju 2014/10/30 18:44:45 Mmm, nope, this was also the original behavior. Th
43 while True: 92 while True:
93 child_thread = TimeoutRetryThread(
94 RunOnTimeoutThread, timeout,
95 name='TimeoutThread-%d-for-%s' % (num_try,
96 threading.current_thread().name))
44 try: 97 try:
45 name = 'TimeoutThread-for-%s' % threading.current_thread().name 98 thread_group = reraiser_thread.ReraiserThreadGroup([child_thread])
46 thread_group = reraiser_thread.ReraiserThreadGroup(
47 [TimeoutRetryThread(RunOnTimeoutThread, name=name)])
48 thread_group.StartAll() 99 thread_group.StartAll()
49 thread_group.JoinAll(watchdog_timer.WatchdogTimer(timeout)) 100 thread_group.JoinAll(child_thread.GetWatcher())
perezju 2014/10/29 18:16:50 This is so that both the thread_group and the time
50 return ret[0] 101 return ret[0]
51 except: 102 except:
52 if retries <= 0: 103 if num_try > retries:
53 raise 104 raise
54 retries -= 1 105 num_try += 1
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698