1 // Copyright (c) 2011 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.
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.
16 // Sample RepeatingTimer usage:
20 // void StartDoingStuff() {
21 // timer_.Start(TimeDelta::FromSeconds(1), this, &MyClass::DoStuff);
23 // void StopDoingStuff() {
28 // // This method is called every second to do stuff.
31 // base::RepeatingTimer<MyClass> timer_;
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.
45 // IMPORTANT: If you change timer code, make sure that all tests (including
46 // disabled ones) from timer_unittests.cc pass locally. Some are disabled
47 // because they're flaky on the buildbot, but when you run them locally you
48 // should be able to tell the difference.
50 #include "base/base_export.h"
51 #include "base/location.h"
52 #include "base/logging.h"
53 #include "base/task.h"
54 #include "base/time.h"
60 //-----------------------------------------------------------------------------
61 // This class is an implementation detail of OneShotTimer and RepeatingTimer.
62 // Please do not use this class directly.
64 // This class exists to share code between BaseTimer<T> template instantiations.
66 class BASE_EXPORT BaseTimer_Helper
{
73 // Returns true if the timer is running (i.e., not stopped).
74 bool IsRunning() const {
75 return delayed_task_
!= NULL
;
78 // Returns the current delay for this timer. May only call this method when
79 // the timer is running!
80 TimeDelta
GetCurrentDelay() const {
82 return delayed_task_
->delay_
;
86 BaseTimer_Helper() : delayed_task_(NULL
) {}
88 // We have access to the timer_ member so we can orphan this task.
89 class TimerTask
: public Task
{
91 TimerTask(const tracked_objects::Location
& posted_from
,
93 : posted_from_(posted_from
),
97 virtual ~TimerTask() {}
98 tracked_objects::Location posted_from_
;
99 BaseTimer_Helper
* timer_
;
103 // Used to orphan delayed_task_ so that when it runs it does nothing.
104 void OrphanDelayedTask();
106 // Used to initiated a new delayed task. This has the side-effect of
107 // orphaning delayed_task_ if it is non-null.
108 void InitiateDelayedTask(TimerTask
* timer_task
);
110 TimerTask
* delayed_task_
;
112 DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper
);
115 //-----------------------------------------------------------------------------
116 // This class is an implementation detail of OneShotTimer and RepeatingTimer.
117 // Please do not use this class directly.
118 template <class Receiver
, bool kIsRepeating
>
119 class BaseTimer
: public BaseTimer_Helper
{
121 typedef void (Receiver::*ReceiverMethod
)();
123 // Call this method to start the timer. It is an error to call this method
124 // while the timer is already running.
125 void Start(const tracked_objects::Location
& posted_from
,
128 ReceiverMethod method
) {
129 DCHECK(!IsRunning());
130 InitiateDelayedTask(new TimerTask(posted_from
, delay
, receiver
, method
));
133 // Call this method to stop the timer. It is a no-op if the timer is not
139 // Call this method to reset the timer delay of an already running timer.
142 InitiateDelayedTask(static_cast<TimerTask
*>(delayed_task_
)->Clone());
146 typedef BaseTimer
<Receiver
, kIsRepeating
> SelfType
;
148 class TimerTask
: public BaseTimer_Helper::TimerTask
{
150 TimerTask(const tracked_objects::Location
& posted_from
,
153 ReceiverMethod method
)
154 : BaseTimer_Helper::TimerTask(posted_from
, delay
),
159 virtual ~TimerTask() {
160 // This task may be getting cleared because the MessageLoop has been
161 // destructed. If so, don't leave the Timer with a dangling pointer
162 // to this now-defunct task.
167 if (!timer_
) // timer_ is null if we were orphaned.
173 DispatchToMethod(receiver_
, method_
, Tuple0());
176 TimerTask
* Clone() const {
177 return new TimerTask(posted_from_
, delay_
, receiver_
, method_
);
181 // Inform the Base that the timer is no longer active.
182 void ClearBaseTimer() {
184 SelfType
* self
= static_cast<SelfType
*>(timer_
);
185 // It is possible that the Timer has already been reset, and that this
186 // Task is old. So, if the Timer points to a different task, assume
187 // that the Timer has already taken care of properly setting the task.
188 if (self
->delayed_task_
== this)
189 self
->delayed_task_
= NULL
;
190 // By now the delayed_task_ in the Timer does not point to us anymore.
191 // We should reset our own timer_ because the Timer can not do this
192 // for us in its destructor.
197 // Inform the Base that we're resetting the timer.
198 void ResetBaseTimer() {
200 DCHECK(kIsRepeating
);
201 SelfType
* self
= static_cast<SelfType
*>(timer_
);
206 ReceiverMethod method_
;
210 //-----------------------------------------------------------------------------
211 // A simple, one-shot timer. See usage notes at the top of the file.
212 template <class Receiver
>
213 class OneShotTimer
: public BaseTimer
<Receiver
, false> {};
215 //-----------------------------------------------------------------------------
216 // A simple, repeating timer. See usage notes at the top of the file.
217 template <class Receiver
>
218 class RepeatingTimer
: public BaseTimer
<Receiver
, true> {};
220 //-----------------------------------------------------------------------------
221 // A Delay timer is like The Button from Lost. Once started, you have to keep
222 // calling Reset otherwise it will call the given method in the MessageLoop
225 // Once created, it is inactive until Reset is called. Once |delay| seconds have
226 // passed since the last call to Reset, the callback is made. Once the callback
227 // has been made, it's inactive until Reset is called again.
229 // If destroyed, the timeout is canceled and will not occur even if already
231 template <class Receiver
>
234 typedef void (Receiver::*ReceiverMethod
)();
236 DelayTimer(const tracked_objects::Location
& posted_from
,
239 ReceiverMethod method
)
240 : posted_from_(posted_from
),
251 void DelayFor(TimeDelta delay
) {
252 trigger_time_
= TimeTicks::Now() + delay
;
254 // If we already have a timer that will expire at or before the given delay,
255 // then we have nothing more to do now.
256 if (timer_
.IsRunning() && timer_
.GetCurrentDelay() <= delay
)
259 // The timer isn't running, or will expire too late, so restart it.
261 timer_
.Start(posted_from_
, delay
, this, &DelayTimer
<Receiver
>::Check
);
265 if (trigger_time_
.is_null())
268 // If we have not waited long enough, then wait some more.
269 const TimeTicks now
= TimeTicks::Now();
270 if (now
< trigger_time_
) {
271 DelayFor(trigger_time_
- now
);
275 (receiver_
->*method_
)();
278 tracked_objects::Location posted_from_
;
279 Receiver
*const receiver_
;
280 const ReceiverMethod method_
;
281 const TimeDelta delay_
;
283 OneShotTimer
<DelayTimer
<Receiver
> > timer_
;
284 TimeTicks trigger_time_
;
289 #endif // BASE_TIMER_H_