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