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.
4 :
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.
40 :
41 : #ifndef BASE_TIMER_H_
42 : #define BASE_TIMER_H_
43 :
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.
48 :
49 : #include "base/logging.h"
50 : #include "base/task.h"
51 : #include "base/time.h"
52 :
53 : class MessageLoop;
54 :
55 : namespace base {
56 :
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 0 : ~BaseTimer_Helper() {
67 0 : OrphanDelayedTask();
68 0 : }
69 :
70 : // Returns true if the timer is running (i.e., not stopped).
71 0 : bool IsRunning() const {
72 0 : return delayed_task_ != NULL;
73 : }
74 :
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 : }
81 :
82 : protected:
83 0 : BaseTimer_Helper() : delayed_task_(NULL) {}
84 :
85 : // We have access to the timer_ member so we can orphan this task.
86 : class TimerTask : public Task {
87 : public:
88 0 : TimerTask(TimeDelta delay) : delay_(delay) {
89 : // timer_ is set in InitiateDelayedTask.
90 0 : }
91 0 : virtual ~TimerTask() {}
92 : BaseTimer_Helper* timer_;
93 : TimeDelta delay_;
94 : };
95 :
96 : // Used to orphan delayed_task_ so that when it runs it does nothing.
97 : void OrphanDelayedTask();
98 :
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);
102 :
103 : TimerTask* delayed_task_;
104 :
105 : DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper);
106 : };
107 :
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 0 : class BaseTimer : public BaseTimer_Helper {
113 : public:
114 : typedef void (Receiver::*ReceiverMethod)();
115 :
116 : // Call this method to start the timer. It is an error to call this method
117 : // while the timer is already running.
118 0 : void Start(TimeDelta delay, Receiver* receiver, ReceiverMethod method) {
119 0 : DCHECK(!IsRunning());
120 0 : InitiateDelayedTask(new TimerTask(delay, receiver, method));
121 0 : }
122 :
123 : // Call this method to stop the timer. It is a no-op if the timer is not
124 : // running.
125 0 : void Stop() {
126 0 : OrphanDelayedTask();
127 0 : }
128 :
129 : // Call this method to reset the timer delay of an already running timer.
130 0 : void Reset() {
131 0 : DCHECK(IsRunning());
132 0 : InitiateDelayedTask(static_cast<TimerTask*>(delayed_task_)->Clone());
133 0 : }
134 :
135 : private:
136 : typedef BaseTimer<Receiver, kIsRepeating> SelfType;
137 :
138 : class TimerTask : public BaseTimer_Helper::TimerTask {
139 : public:
140 0 : TimerTask(TimeDelta delay, Receiver* receiver, ReceiverMethod method)
141 : : BaseTimer_Helper::TimerTask(delay),
142 : receiver_(receiver),
143 0 : method_(method) {
144 0 : }
145 :
146 0 : 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 0 : ClearBaseTimer();
151 0 : }
152 :
153 0 : virtual void Run() {
154 0 : if (!timer_) // timer_ is null if we were orphaned.
155 0 : return;
156 : if (kIsRepeating)
157 0 : ResetBaseTimer();
158 : else
159 : ClearBaseTimer();
160 0 : DispatchToMethod(receiver_, method_, Tuple0());
161 : }
162 :
163 0 : TimerTask* Clone() const {
164 0 : return new TimerTask(delay_, receiver_, method_);
165 : }
166 :
167 : private:
168 : // Inform the Base that the timer is no longer active.
169 0 : void ClearBaseTimer() {
170 0 : if (timer_) {
171 0 : 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 0 : if (self->delayed_task_ == this)
176 0 : 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 0 : timer_ = NULL;
181 : }
182 0 : }
183 :
184 : // Inform the Base that we're resetting the timer.
185 0 : void ResetBaseTimer() {
186 0 : DCHECK(timer_);
187 : DCHECK(kIsRepeating);
188 0 : SelfType* self = static_cast<SelfType*>(timer_);
189 0 : self->Reset();
190 0 : }
191 :
192 : Receiver* receiver_;
193 : ReceiverMethod method_;
194 : };
195 : };
196 :
197 : //-----------------------------------------------------------------------------
198 : // A simple, one-shot timer. See usage notes at the top of the file.
199 : template <class Receiver>
200 0 : class OneShotTimer : public BaseTimer<Receiver, false> {};
201 :
202 : //-----------------------------------------------------------------------------
203 : // A simple, repeating timer. See usage notes at the top of the file.
204 : template <class Receiver>
205 0 : class RepeatingTimer : public BaseTimer<Receiver, true> {};
206 :
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)();
222 :
223 : DelayTimer(TimeDelta delay, Receiver* receiver, ReceiverMethod method)
224 : : receiver_(receiver),
225 : method_(method),
226 : delay_(delay) {
227 : }
228 :
229 : void Reset() {
230 : DelayFor(delay_);
231 : }
232 :
233 : private:
234 : void DelayFor(TimeDelta delay) {
235 : trigger_time_ = Time::Now() + delay;
236 :
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;
241 :
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 : }
246 :
247 : void Check() {
248 : if (trigger_time_.is_null())
249 : return;
250 :
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 : }
257 :
258 : (receiver_->*method_)();
259 : }
260 :
261 : Receiver *const receiver_;
262 : const ReceiverMethod method_;
263 : const TimeDelta delay_;
264 :
265 : OneShotTimer<DelayTimer<Receiver> > timer_;
266 : Time trigger_time_;
267 : };
268 :
269 : } // namespace base
270 :
271 : #endif // BASE_TIMER_H_
|