Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 // Copyright (c) 2006-2008 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.
5 // OneShotTimer and RepeatingTimer provide a simple timer API. As the names
6 // suggest, OneShotTimer calls you back once after a time delay expires.
7 // RepeatingTimer on the other hand calls you back periodically with the
8 // prescribed time interval.
9 //
10 // OneShotTimer and RepeatingTimer both cancel the timer when they go out of
11 // scope, which makes it easy to ensure that you do not get called when your
12 // object has gone out of scope. Just instantiate a OneShotTimer or
13 // RepeatingTimer as a member variable of the class for which you wish to
14 // receive timer events.
15 //
16 // Sample RepeatingTimer usage:
17 //
18 // class MyClass {
19 // public:
20 // void StartDoingStuff() {
21 // timer_.Start(TimeDelta::FromSeconds(1), this, &MyClass::DoStuff);
22 // }
23 // void StopDoingStuff() {
24 // timer_.Stop();
25 // }
26 // private:
27 // void DoStuff() {
28 // // This method is called every second to do stuff.
29 // ...
30 // }
31 // base::RepeatingTimer<MyClass> timer_;
32 // };
33 //
34 // Both OneShotTimer and RepeatingTimer also support a Reset method, which
35 // allows you to easily defer the timer event until the timer delay passes once
36 // again. So, in the above example, if 0.5 seconds have already passed,
37 // calling Reset on timer_ would postpone DoStuff by another 1 second. In
38 // other words, Reset is shorthand for calling Stop and then Start again with
39 // the same arguments.
41 #ifndef BASE_TIMER_H_
42 #define BASE_TIMER_H_
44 // IMPORTANT: If you change timer code, make sure that all tests (including
45 // disabled ones) from timer_unittests.cc pass locally. Some are disabled
46 // because they're flaky on the buildbot, but when you run them locally you
47 // should be able to tell the difference.
49 #include "base/logging.h"
50 #include "base/task.h"
51 #include "base/time.h"
53 class MessageLoop;
55 namespace base {
57 //-----------------------------------------------------------------------------
58 // This class is an implementation detail of OneShotTimer and RepeatingTimer.
59 // Please do not use this class directly.
60 //
61 // This class exists to share code between BaseTimer<T> template instantiations.
62 //
63 class BaseTimer_Helper {
64 public:
65 // Stops the timer.
66 ~BaseTimer_Helper() {
67 OrphanDelayedTask();
68 }
70 // Returns true if the timer is running (i.e., not stopped).
71 bool IsRunning() const {
72 return delayed_task_ != NULL;
73 }
75 // Returns the current delay for this timer. May only call this method when
76 // the timer is running!
77 TimeDelta GetCurrentDelay() const {
78 DCHECK(IsRunning());
79 return delayed_task_->delay_;
80 }
82 protected:
83 BaseTimer_Helper() : delayed_task_(NULL) {}
85 // We have access to the timer_ member so we can orphan this task.
86 class TimerTask : public Task {
87 public:
88 TimerTask(TimeDelta delay) : delay_(delay) {
89 // timer_ is set in InitiateDelayedTask.
90 }
91 virtual ~TimerTask() {}
92 BaseTimer_Helper* timer_;
93 TimeDelta delay_;
94 };
96 // Used to orphan delayed_task_ so that when it runs it does nothing.
97 void OrphanDelayedTask();
99 // Used to initiated a new delayed task. This has the side-effect of
100 // orphaning delayed_task_ if it is non-null.
101 void InitiateDelayedTask(TimerTask* timer_task);
103 TimerTask* delayed_task_;
105 DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper);
106 };
108 //-----------------------------------------------------------------------------
109 // This class is an implementation detail of OneShotTimer and RepeatingTimer.
110 // Please do not use this class directly.
111 template <class Receiver, bool kIsRepeating>
112 class BaseTimer : public BaseTimer_Helper {
113 public:
114 typedef void (Receiver::*ReceiverMethod)();
116 // Call this method to start the timer. It is an error to call this method
117 // while the timer is already running.
118 void Start(TimeDelta delay, Receiver* receiver, ReceiverMethod method) {
119 DCHECK(!IsRunning());
120 InitiateDelayedTask(new TimerTask(delay, receiver, method));
121 }
123 // Call this method to stop the timer. It is a no-op if the timer is not
124 // running.
125 void Stop() {
126 OrphanDelayedTask();
127 }
129 // Call this method to reset the timer delay of an already running timer.
130 void Reset() {
131 DCHECK(IsRunning());
132 InitiateDelayedTask(static_cast<TimerTask*>(delayed_task_)->Clone());
133 }
135 private:
136 typedef BaseTimer<Receiver, kIsRepeating> SelfType;
138 class TimerTask : public BaseTimer_Helper::TimerTask {
139 public:
140 TimerTask(TimeDelta delay, Receiver* receiver, ReceiverMethod method)
141 : BaseTimer_Helper::TimerTask(delay),
142 receiver_(receiver),
143 method_(method) {
144 }
146 virtual ~TimerTask() {
147 // This task may be getting cleared because the MessageLoop has been
148 // destructed. If so, don't leave the Timer with a dangling pointer
149 // to this now-defunct task.
150 ClearBaseTimer();
151 }
153 virtual void Run() {
154 if (!timer_) // timer_ is null if we were orphaned.
155 return;
156 if (kIsRepeating)
157 ResetBaseTimer();
158 else
159 ClearBaseTimer();
160 DispatchToMethod(receiver_, method_, Tuple0());
161 }
163 TimerTask* Clone() const {
164 return new TimerTask(delay_, receiver_, method_);
165 }
167 private:
168 // Inform the Base that the timer is no longer active.
169 void ClearBaseTimer() {
170 if (timer_) {
171 SelfType* self = static_cast<SelfType*>(timer_);
172 // It is possible that the Timer has already been reset, and that this
173 // Task is old. So, if the Timer points to a different task, assume
174 // that the Timer has already taken care of properly setting the task.
175 if (self->delayed_task_ == this)
176 self->delayed_task_ = NULL;
177 // By now the delayed_task_ in the Timer does not point to us anymore.
178 // We should reset our own timer_ because the Timer can not do this
179 // for us in its destructor.
180 timer_ = NULL;
181 }
182 }
184 // Inform the Base that we're resetting the timer.
185 void ResetBaseTimer() {
186 DCHECK(timer_);
187 DCHECK(kIsRepeating);
188 SelfType* self = static_cast<SelfType*>(timer_);
189 self->Reset();
190 }
192 Receiver* receiver_;
193 ReceiverMethod method_;
194 };
195 };
197 //-----------------------------------------------------------------------------
198 // A simple, one-shot timer. See usage notes at the top of the file.
199 template <class Receiver>
200 class OneShotTimer : public BaseTimer<Receiver, false> {};
202 //-----------------------------------------------------------------------------
203 // A simple, repeating timer. See usage notes at the top of the file.
204 template <class Receiver>
205 class RepeatingTimer : public BaseTimer<Receiver, true> {};
207 //-----------------------------------------------------------------------------
208 // A Delay timer is like The Button from Lost. Once started, you have to keep
209 // calling Reset otherwise it will call the given method in the MessageLoop
210 // thread.
211 //
212 // Once created, it is inactive until Reset is called. Once |delay| seconds have
213 // passed since the last call to Reset, the callback is made. Once the callback
214 // has been made, it's inactive until Reset is called again.
215 //
216 // If destroyed, the timeout is canceled and will not occur even if already
217 // inflight.
218 template <class Receiver>
219 class DelayTimer {
220 public:
221 typedef void (Receiver::*ReceiverMethod)();
223 DelayTimer(TimeDelta delay, Receiver* receiver, ReceiverMethod method)
224 : receiver_(receiver),
225 method_(method),
226 delay_(delay) {
227 }
229 void Reset() {
230 DelayFor(delay_);
231 }
233 private:
234 void DelayFor(TimeDelta delay) {
235 trigger_time_ = Time::Now() + delay;
237 // If we already have a timer that will expire at or before the given delay,
238 // then we have nothing more to do now.
239 if (timer_.IsRunning() && timer_.GetCurrentDelay() <= delay)
240 return;
242 // The timer isn't running, or will expire too late, so restart it.
243 timer_.Stop();
244 timer_.Start(delay, this, &DelayTimer<Receiver>::Check);
245 }
247 void Check() {
248 if (trigger_time_.is_null())
249 return;
251 // If we have not waited long enough, then wait some more.
252 const Time now = Time::Now();
253 if (now < trigger_time_) {
254 DelayFor(trigger_time_ - now);
255 return;
256 }
258 (receiver_->*method_)();
259 }
261 Receiver *const receiver_;
262 const ReceiverMethod method_;
263 const TimeDelta delay_;
265 OneShotTimer<DelayTimer<Receiver> > timer_;
266 Time trigger_time_;
267 };
269 } // namespace base
271 #endif // BASE_TIMER_H_