| 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 |