Chromium Code Reviews| 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 explicit TimerTask(TimeDelta delay, |
| 91 const tracked_objects::Location& posted_from) | |
| 92 : timer_(NULL), | |
| 93 delay_(delay), | |
| 94 posted_from_(posted_from) { | |
| 91 } | 95 } |
| 92 virtual ~TimerTask() {} | 96 virtual ~TimerTask() {} |
| 93 BaseTimer_Helper* timer_; | 97 BaseTimer_Helper* timer_; |
| 94 TimeDelta delay_; | 98 TimeDelta delay_; |
| 99 tracked_objects::Location posted_from_; | |
| 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(TimeDelta delay, |
|
darin (slow to review)
2011/08/31 21:27:38
consistency nit: it'd be nice to place the Locati
jbates
2011/08/31 23:01:59
Done.
| |
| 125 Receiver* receiver, | |
| 126 ReceiverMethod method, | |
| 127 const tracked_objects::Location& posted_from) { | |
| 120 DCHECK(!IsRunning()); | 128 DCHECK(!IsRunning()); |
| 121 InitiateDelayedTask(new TimerTask(delay, receiver, method)); | 129 InitiateDelayedTask(new TimerTask(delay, receiver, method, posted_from)); |
| 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(TimeDelta delay, |
| 142 : BaseTimer_Helper::TimerTask(delay), | 150 Receiver* receiver, |
| 151 ReceiverMethod method, | |
| 152 const tracked_objects::Location& posted_from) | |
| 153 : BaseTimer_Helper::TimerTask(delay, posted_from), | |
| 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(delay_, receiver_, method_, posted_from_); |
| 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(TimeDelta delay, |
| 236 Receiver* receiver, | |
| 237 ReceiverMethod method, | |
| 238 const tracked_objects::Location& posted_from) | |
| 225 : receiver_(receiver), | 239 : receiver_(receiver), |
| 226 method_(method), | 240 method_(method), |
| 227 delay_(delay) { | 241 delay_(delay), |
| 242 posted_from_(posted_from) { | |
| 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(delay, this, &DelayTimer<Receiver>::Check, posted_from_); |
| 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 |
| 262 Receiver *const receiver_; | 277 Receiver *const receiver_; |
| 263 const ReceiverMethod method_; | 278 const ReceiverMethod method_; |
| 264 const TimeDelta delay_; | 279 const TimeDelta delay_; |
| 280 tracked_objects::Location posted_from_; | |
| 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 |