1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/timer.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,271 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +// OneShotTimer and RepeatingTimer provide a simple timer API. As the names 1.9 +// suggest, OneShotTimer calls you back once after a time delay expires. 1.10 +// RepeatingTimer on the other hand calls you back periodically with the 1.11 +// prescribed time interval. 1.12 +// 1.13 +// OneShotTimer and RepeatingTimer both cancel the timer when they go out of 1.14 +// scope, which makes it easy to ensure that you do not get called when your 1.15 +// object has gone out of scope. Just instantiate a OneShotTimer or 1.16 +// RepeatingTimer as a member variable of the class for which you wish to 1.17 +// receive timer events. 1.18 +// 1.19 +// Sample RepeatingTimer usage: 1.20 +// 1.21 +// class MyClass { 1.22 +// public: 1.23 +// void StartDoingStuff() { 1.24 +// timer_.Start(TimeDelta::FromSeconds(1), this, &MyClass::DoStuff); 1.25 +// } 1.26 +// void StopDoingStuff() { 1.27 +// timer_.Stop(); 1.28 +// } 1.29 +// private: 1.30 +// void DoStuff() { 1.31 +// // This method is called every second to do stuff. 1.32 +// ... 1.33 +// } 1.34 +// base::RepeatingTimer<MyClass> timer_; 1.35 +// }; 1.36 +// 1.37 +// Both OneShotTimer and RepeatingTimer also support a Reset method, which 1.38 +// allows you to easily defer the timer event until the timer delay passes once 1.39 +// again. So, in the above example, if 0.5 seconds have already passed, 1.40 +// calling Reset on timer_ would postpone DoStuff by another 1 second. In 1.41 +// other words, Reset is shorthand for calling Stop and then Start again with 1.42 +// the same arguments. 1.43 + 1.44 +#ifndef BASE_TIMER_H_ 1.45 +#define BASE_TIMER_H_ 1.46 + 1.47 +// IMPORTANT: If you change timer code, make sure that all tests (including 1.48 +// disabled ones) from timer_unittests.cc pass locally. Some are disabled 1.49 +// because they're flaky on the buildbot, but when you run them locally you 1.50 +// should be able to tell the difference. 1.51 + 1.52 +#include "base/logging.h" 1.53 +#include "base/task.h" 1.54 +#include "base/time.h" 1.55 + 1.56 +class MessageLoop; 1.57 + 1.58 +namespace base { 1.59 + 1.60 +//----------------------------------------------------------------------------- 1.61 +// This class is an implementation detail of OneShotTimer and RepeatingTimer. 1.62 +// Please do not use this class directly. 1.63 +// 1.64 +// This class exists to share code between BaseTimer<T> template instantiations. 1.65 +// 1.66 +class BaseTimer_Helper { 1.67 + public: 1.68 + // Stops the timer. 1.69 + ~BaseTimer_Helper() { 1.70 + OrphanDelayedTask(); 1.71 + } 1.72 + 1.73 + // Returns true if the timer is running (i.e., not stopped). 1.74 + bool IsRunning() const { 1.75 + return delayed_task_ != NULL; 1.76 + } 1.77 + 1.78 + // Returns the current delay for this timer. May only call this method when 1.79 + // the timer is running! 1.80 + TimeDelta GetCurrentDelay() const { 1.81 + DCHECK(IsRunning()); 1.82 + return delayed_task_->delay_; 1.83 + } 1.84 + 1.85 + protected: 1.86 + BaseTimer_Helper() : delayed_task_(NULL) {} 1.87 + 1.88 + // We have access to the timer_ member so we can orphan this task. 1.89 + class TimerTask : public Task { 1.90 + public: 1.91 + TimerTask(TimeDelta delay) : delay_(delay) { 1.92 + // timer_ is set in InitiateDelayedTask. 1.93 + } 1.94 + virtual ~TimerTask() {} 1.95 + BaseTimer_Helper* timer_; 1.96 + TimeDelta delay_; 1.97 + }; 1.98 + 1.99 + // Used to orphan delayed_task_ so that when it runs it does nothing. 1.100 + void OrphanDelayedTask(); 1.101 + 1.102 + // Used to initiated a new delayed task. This has the side-effect of 1.103 + // orphaning delayed_task_ if it is non-null. 1.104 + void InitiateDelayedTask(TimerTask* timer_task); 1.105 + 1.106 + TimerTask* delayed_task_; 1.107 + 1.108 + DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper); 1.109 +}; 1.110 + 1.111 +//----------------------------------------------------------------------------- 1.112 +// This class is an implementation detail of OneShotTimer and RepeatingTimer. 1.113 +// Please do not use this class directly. 1.114 +template <class Receiver, bool kIsRepeating> 1.115 +class BaseTimer : public BaseTimer_Helper { 1.116 + public: 1.117 + typedef void (Receiver::*ReceiverMethod)(); 1.118 + 1.119 + // Call this method to start the timer. It is an error to call this method 1.120 + // while the timer is already running. 1.121 + void Start(TimeDelta delay, Receiver* receiver, ReceiverMethod method) { 1.122 + DCHECK(!IsRunning()); 1.123 + InitiateDelayedTask(new TimerTask(delay, receiver, method)); 1.124 + } 1.125 + 1.126 + // Call this method to stop the timer. It is a no-op if the timer is not 1.127 + // running. 1.128 + void Stop() { 1.129 + OrphanDelayedTask(); 1.130 + } 1.131 + 1.132 + // Call this method to reset the timer delay of an already running timer. 1.133 + void Reset() { 1.134 + DCHECK(IsRunning()); 1.135 + InitiateDelayedTask(static_cast<TimerTask*>(delayed_task_)->Clone()); 1.136 + } 1.137 + 1.138 + private: 1.139 + typedef BaseTimer<Receiver, kIsRepeating> SelfType; 1.140 + 1.141 + class TimerTask : public BaseTimer_Helper::TimerTask { 1.142 + public: 1.143 + TimerTask(TimeDelta delay, Receiver* receiver, ReceiverMethod method) 1.144 + : BaseTimer_Helper::TimerTask(delay), 1.145 + receiver_(receiver), 1.146 + method_(method) { 1.147 + } 1.148 + 1.149 + virtual ~TimerTask() { 1.150 + // This task may be getting cleared because the MessageLoop has been 1.151 + // destructed. If so, don't leave the Timer with a dangling pointer 1.152 + // to this now-defunct task. 1.153 + ClearBaseTimer(); 1.154 + } 1.155 + 1.156 + virtual void Run() { 1.157 + if (!timer_) // timer_ is null if we were orphaned. 1.158 + return; 1.159 + if (kIsRepeating) 1.160 + ResetBaseTimer(); 1.161 + else 1.162 + ClearBaseTimer(); 1.163 + DispatchToMethod(receiver_, method_, Tuple0()); 1.164 + } 1.165 + 1.166 + TimerTask* Clone() const { 1.167 + return new TimerTask(delay_, receiver_, method_); 1.168 + } 1.169 + 1.170 + private: 1.171 + // Inform the Base that the timer is no longer active. 1.172 + void ClearBaseTimer() { 1.173 + if (timer_) { 1.174 + SelfType* self = static_cast<SelfType*>(timer_); 1.175 + // It is possible that the Timer has already been reset, and that this 1.176 + // Task is old. So, if the Timer points to a different task, assume 1.177 + // that the Timer has already taken care of properly setting the task. 1.178 + if (self->delayed_task_ == this) 1.179 + self->delayed_task_ = NULL; 1.180 + // By now the delayed_task_ in the Timer does not point to us anymore. 1.181 + // We should reset our own timer_ because the Timer can not do this 1.182 + // for us in its destructor. 1.183 + timer_ = NULL; 1.184 + } 1.185 + } 1.186 + 1.187 + // Inform the Base that we're resetting the timer. 1.188 + void ResetBaseTimer() { 1.189 + DCHECK(timer_); 1.190 + DCHECK(kIsRepeating); 1.191 + SelfType* self = static_cast<SelfType*>(timer_); 1.192 + self->Reset(); 1.193 + } 1.194 + 1.195 + Receiver* receiver_; 1.196 + ReceiverMethod method_; 1.197 + }; 1.198 +}; 1.199 + 1.200 +//----------------------------------------------------------------------------- 1.201 +// A simple, one-shot timer. See usage notes at the top of the file. 1.202 +template <class Receiver> 1.203 +class OneShotTimer : public BaseTimer<Receiver, false> {}; 1.204 + 1.205 +//----------------------------------------------------------------------------- 1.206 +// A simple, repeating timer. See usage notes at the top of the file. 1.207 +template <class Receiver> 1.208 +class RepeatingTimer : public BaseTimer<Receiver, true> {}; 1.209 + 1.210 +//----------------------------------------------------------------------------- 1.211 +// A Delay timer is like The Button from Lost. Once started, you have to keep 1.212 +// calling Reset otherwise it will call the given method in the MessageLoop 1.213 +// thread. 1.214 +// 1.215 +// Once created, it is inactive until Reset is called. Once |delay| seconds have 1.216 +// passed since the last call to Reset, the callback is made. Once the callback 1.217 +// has been made, it's inactive until Reset is called again. 1.218 +// 1.219 +// If destroyed, the timeout is canceled and will not occur even if already 1.220 +// inflight. 1.221 +template <class Receiver> 1.222 +class DelayTimer { 1.223 + public: 1.224 + typedef void (Receiver::*ReceiverMethod)(); 1.225 + 1.226 + DelayTimer(TimeDelta delay, Receiver* receiver, ReceiverMethod method) 1.227 + : receiver_(receiver), 1.228 + method_(method), 1.229 + delay_(delay) { 1.230 + } 1.231 + 1.232 + void Reset() { 1.233 + DelayFor(delay_); 1.234 + } 1.235 + 1.236 + private: 1.237 + void DelayFor(TimeDelta delay) { 1.238 + trigger_time_ = Time::Now() + delay; 1.239 + 1.240 + // If we already have a timer that will expire at or before the given delay, 1.241 + // then we have nothing more to do now. 1.242 + if (timer_.IsRunning() && timer_.GetCurrentDelay() <= delay) 1.243 + return; 1.244 + 1.245 + // The timer isn't running, or will expire too late, so restart it. 1.246 + timer_.Stop(); 1.247 + timer_.Start(delay, this, &DelayTimer<Receiver>::Check); 1.248 + } 1.249 + 1.250 + void Check() { 1.251 + if (trigger_time_.is_null()) 1.252 + return; 1.253 + 1.254 + // If we have not waited long enough, then wait some more. 1.255 + const Time now = Time::Now(); 1.256 + if (now < trigger_time_) { 1.257 + DelayFor(trigger_time_ - now); 1.258 + return; 1.259 + } 1.260 + 1.261 + (receiver_->*method_)(); 1.262 + } 1.263 + 1.264 + Receiver *const receiver_; 1.265 + const ReceiverMethod method_; 1.266 + const TimeDelta delay_; 1.267 + 1.268 + OneShotTimer<DelayTimer<Receiver> > timer_; 1.269 + Time trigger_time_; 1.270 +}; 1.271 + 1.272 +} // namespace base 1.273 + 1.274 +#endif // BASE_TIMER_H_