OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 // OneShotTimer and RepeatingTimer provide a simple timer API. As the names | 5 // OneShotTimer and RepeatingTimer provide a simple timer API. As the names |
6 // suggest, OneShotTimer calls you back once after a time delay expires. | 6 // suggest, OneShotTimer calls you back once after a time delay expires. |
7 // RepeatingTimer on the other hand calls you back periodically with the | 7 // RepeatingTimer on the other hand calls you back periodically with the |
8 // prescribed time interval. | 8 // prescribed time interval. |
9 // | 9 // |
10 // OneShotTimer and RepeatingTimer both cancel the timer when they go out of | 10 // OneShotTimer and RepeatingTimer both cancel the timer when they go out of |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 DCHECK(IsRunning()); | 80 DCHECK(IsRunning()); |
81 return delayed_task_->delay_; | 81 return delayed_task_->delay_; |
82 } | 82 } |
83 | 83 |
84 protected: | 84 protected: |
85 BaseTimer_Helper() : delayed_task_(NULL) {} | 85 BaseTimer_Helper() : delayed_task_(NULL) {} |
86 | 86 |
87 // We have access to the timer_ member so we can orphan this task. | 87 // We have access to the timer_ member so we can orphan this task. |
88 class TimerTask : public Task { | 88 class TimerTask : public Task { |
89 public: | 89 public: |
90 TimerTask(const tracked_objects::Location& posted_from, | 90 explicit TimerTask(TimeDelta delay) : timer_(NULL), delay_(delay) { |
91 TimeDelta delay) | |
92 : posted_from_(posted_from), | |
93 timer_(NULL), | |
94 delay_(delay) { | |
95 } | 91 } |
96 virtual ~TimerTask() {} | 92 virtual ~TimerTask() {} |
97 tracked_objects::Location posted_from_; | |
98 BaseTimer_Helper* timer_; | 93 BaseTimer_Helper* timer_; |
99 TimeDelta delay_; | 94 TimeDelta delay_; |
100 }; | 95 }; |
101 | 96 |
102 // Used to orphan delayed_task_ so that when it runs it does nothing. | 97 // Used to orphan delayed_task_ so that when it runs it does nothing. |
103 void OrphanDelayedTask(); | 98 void OrphanDelayedTask(); |
104 | 99 |
105 // Used to initiated a new delayed task. This has the side-effect of | 100 // Used to initiated a new delayed task. This has the side-effect of |
106 // orphaning delayed_task_ if it is non-null. | 101 // orphaning delayed_task_ if it is non-null. |
107 void InitiateDelayedTask(TimerTask* timer_task); | 102 void InitiateDelayedTask(TimerTask* timer_task); |
108 | 103 |
109 TimerTask* delayed_task_; | 104 TimerTask* delayed_task_; |
110 | 105 |
111 DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper); | 106 DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper); |
112 }; | 107 }; |
113 | 108 |
114 //----------------------------------------------------------------------------- | 109 //----------------------------------------------------------------------------- |
115 // This class is an implementation detail of OneShotTimer and RepeatingTimer. | 110 // This class is an implementation detail of OneShotTimer and RepeatingTimer. |
116 // Please do not use this class directly. | 111 // Please do not use this class directly. |
117 template <class Receiver, bool kIsRepeating> | 112 template <class Receiver, bool kIsRepeating> |
118 class BaseTimer : public BaseTimer_Helper { | 113 class BaseTimer : public BaseTimer_Helper { |
119 public: | 114 public: |
120 typedef void (Receiver::*ReceiverMethod)(); | 115 typedef void (Receiver::*ReceiverMethod)(); |
121 | 116 |
122 // Call this method to start the timer. It is an error to call this method | 117 // Call this method to start the timer. It is an error to call this method |
123 // while the timer is already running. | 118 // while the timer is already running. |
124 void Start(const tracked_objects::Location& posted_from, | 119 void Start(TimeDelta delay, Receiver* receiver, ReceiverMethod method) { |
125 TimeDelta delay, | |
126 Receiver* receiver, | |
127 ReceiverMethod method) { | |
128 DCHECK(!IsRunning()); | 120 DCHECK(!IsRunning()); |
129 InitiateDelayedTask(new TimerTask(posted_from, delay, receiver, method)); | 121 InitiateDelayedTask(new TimerTask(delay, receiver, method)); |
130 } | 122 } |
131 | 123 |
132 // Call this method to stop the timer. It is a no-op if the timer is not | 124 // Call this method to stop the timer. It is a no-op if the timer is not |
133 // running. | 125 // running. |
134 void Stop() { | 126 void Stop() { |
135 OrphanDelayedTask(); | 127 OrphanDelayedTask(); |
136 } | 128 } |
137 | 129 |
138 // Call this method to reset the timer delay of an already running timer. | 130 // Call this method to reset the timer delay of an already running timer. |
139 void Reset() { | 131 void Reset() { |
140 DCHECK(IsRunning()); | 132 DCHECK(IsRunning()); |
141 InitiateDelayedTask(static_cast<TimerTask*>(delayed_task_)->Clone()); | 133 InitiateDelayedTask(static_cast<TimerTask*>(delayed_task_)->Clone()); |
142 } | 134 } |
143 | 135 |
144 private: | 136 private: |
145 typedef BaseTimer<Receiver, kIsRepeating> SelfType; | 137 typedef BaseTimer<Receiver, kIsRepeating> SelfType; |
146 | 138 |
147 class TimerTask : public BaseTimer_Helper::TimerTask { | 139 class TimerTask : public BaseTimer_Helper::TimerTask { |
148 public: | 140 public: |
149 TimerTask(const tracked_objects::Location& posted_from, | 141 TimerTask(TimeDelta delay, Receiver* receiver, ReceiverMethod method) |
150 TimeDelta delay, | 142 : BaseTimer_Helper::TimerTask(delay), |
151 Receiver* receiver, | |
152 ReceiverMethod method) | |
153 : BaseTimer_Helper::TimerTask(posted_from, delay), | |
154 receiver_(receiver), | 143 receiver_(receiver), |
155 method_(method) { | 144 method_(method) { |
156 } | 145 } |
157 | 146 |
158 virtual ~TimerTask() { | 147 virtual ~TimerTask() { |
159 // This task may be getting cleared because the MessageLoop has been | 148 // This task may be getting cleared because the MessageLoop has been |
160 // destructed. If so, don't leave the Timer with a dangling pointer | 149 // destructed. If so, don't leave the Timer with a dangling pointer |
161 // to this now-defunct task. | 150 // to this now-defunct task. |
162 ClearBaseTimer(); | 151 ClearBaseTimer(); |
163 } | 152 } |
164 | 153 |
165 virtual void Run() { | 154 virtual void Run() { |
166 if (!timer_) // timer_ is null if we were orphaned. | 155 if (!timer_) // timer_ is null if we were orphaned. |
167 return; | 156 return; |
168 if (kIsRepeating) | 157 if (kIsRepeating) |
169 ResetBaseTimer(); | 158 ResetBaseTimer(); |
170 else | 159 else |
171 ClearBaseTimer(); | 160 ClearBaseTimer(); |
172 DispatchToMethod(receiver_, method_, Tuple0()); | 161 DispatchToMethod(receiver_, method_, Tuple0()); |
173 } | 162 } |
174 | 163 |
175 TimerTask* Clone() const { | 164 TimerTask* Clone() const { |
176 return new TimerTask(posted_from_, delay_, receiver_, method_); | 165 return new TimerTask(delay_, receiver_, method_); |
177 } | 166 } |
178 | 167 |
179 private: | 168 private: |
180 // Inform the Base that the timer is no longer active. | 169 // Inform the Base that the timer is no longer active. |
181 void ClearBaseTimer() { | 170 void ClearBaseTimer() { |
182 if (timer_) { | 171 if (timer_) { |
183 SelfType* self = static_cast<SelfType*>(timer_); | 172 SelfType* self = static_cast<SelfType*>(timer_); |
184 // It is possible that the Timer has already been reset, and that this | 173 // It is possible that the Timer has already been reset, and that this |
185 // Task is old. So, if the Timer points to a different task, assume | 174 // Task is old. So, if the Timer points to a different task, assume |
186 // that the Timer has already taken care of properly setting the task. | 175 // that the Timer has already taken care of properly setting the task. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 // passed since the last call to Reset, the callback is made. Once the callback | 214 // passed since the last call to Reset, the callback is made. Once the callback |
226 // has been made, it's inactive until Reset is called again. | 215 // has been made, it's inactive until Reset is called again. |
227 // | 216 // |
228 // If destroyed, the timeout is canceled and will not occur even if already | 217 // If destroyed, the timeout is canceled and will not occur even if already |
229 // inflight. | 218 // inflight. |
230 template <class Receiver> | 219 template <class Receiver> |
231 class DelayTimer { | 220 class DelayTimer { |
232 public: | 221 public: |
233 typedef void (Receiver::*ReceiverMethod)(); | 222 typedef void (Receiver::*ReceiverMethod)(); |
234 | 223 |
235 DelayTimer(const tracked_objects::Location& posted_from, | 224 DelayTimer(TimeDelta delay, Receiver* receiver, ReceiverMethod method) |
236 TimeDelta delay, | 225 : receiver_(receiver), |
237 Receiver* receiver, | |
238 ReceiverMethod method) | |
239 : posted_from_(posted_from), | |
240 receiver_(receiver), | |
241 method_(method), | 226 method_(method), |
242 delay_(delay) { | 227 delay_(delay) { |
243 } | 228 } |
244 | 229 |
245 void Reset() { | 230 void Reset() { |
246 DelayFor(delay_); | 231 DelayFor(delay_); |
247 } | 232 } |
248 | 233 |
249 private: | 234 private: |
250 void DelayFor(TimeDelta delay) { | 235 void DelayFor(TimeDelta delay) { |
251 trigger_time_ = TimeTicks::Now() + delay; | 236 trigger_time_ = TimeTicks::Now() + delay; |
252 | 237 |
253 // If we already have a timer that will expire at or before the given delay, | 238 // If we already have a timer that will expire at or before the given delay, |
254 // then we have nothing more to do now. | 239 // then we have nothing more to do now. |
255 if (timer_.IsRunning() && timer_.GetCurrentDelay() <= delay) | 240 if (timer_.IsRunning() && timer_.GetCurrentDelay() <= delay) |
256 return; | 241 return; |
257 | 242 |
258 // The timer isn't running, or will expire too late, so restart it. | 243 // The timer isn't running, or will expire too late, so restart it. |
259 timer_.Stop(); | 244 timer_.Stop(); |
260 timer_.Start(posted_from_, delay, this, &DelayTimer<Receiver>::Check); | 245 timer_.Start(delay, this, &DelayTimer<Receiver>::Check); |
261 } | 246 } |
262 | 247 |
263 void Check() { | 248 void Check() { |
264 if (trigger_time_.is_null()) | 249 if (trigger_time_.is_null()) |
265 return; | 250 return; |
266 | 251 |
267 // If we have not waited long enough, then wait some more. | 252 // If we have not waited long enough, then wait some more. |
268 const TimeTicks now = TimeTicks::Now(); | 253 const TimeTicks now = TimeTicks::Now(); |
269 if (now < trigger_time_) { | 254 if (now < trigger_time_) { |
270 DelayFor(trigger_time_ - now); | 255 DelayFor(trigger_time_ - now); |
271 return; | 256 return; |
272 } | 257 } |
273 | 258 |
274 (receiver_->*method_)(); | 259 (receiver_->*method_)(); |
275 } | 260 } |
276 | 261 |
277 tracked_objects::Location posted_from_; | |
278 Receiver *const receiver_; | 262 Receiver *const receiver_; |
279 const ReceiverMethod method_; | 263 const ReceiverMethod method_; |
280 const TimeDelta delay_; | 264 const TimeDelta delay_; |
281 | 265 |
282 OneShotTimer<DelayTimer<Receiver> > timer_; | 266 OneShotTimer<DelayTimer<Receiver> > timer_; |
283 TimeTicks trigger_time_; | 267 TimeTicks trigger_time_; |
284 }; | 268 }; |
285 | 269 |
286 } // namespace base | 270 } // namespace base |
287 | 271 |
288 #endif // BASE_TIMER_H_ | 272 #endif // BASE_TIMER_H_ |
OLD | NEW |