1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // OneShotTimer and RepeatingTimer provide a simple timer API. As the names 6 // suggest, OneShotTimer calls you back once after a time delay expires. 7 // RepeatingTimer on the other hand calls you back periodically with the 8 // prescribed time interval. 9 // 10 // OneShotTimer and RepeatingTimer both cancel the timer when they go out of 11 // scope, which makes it easy to ensure that you do not get called when your 12 // object has gone out of scope. Just instantiate a OneShotTimer or 13 // RepeatingTimer as a member variable of the class for which you wish to 14 // receive timer events. 15 // 16 // Sample RepeatingTimer usage: 17 // 18 // class MyClass { 19 // public: 20 // void StartDoingStuff() { 21 // timer_.Start(FROM_HERE, TimeDelta::FromSeconds(1), 22 // this, &MyClass::DoStuff); 23 // } 24 // void StopDoingStuff() { 25 // timer_.Stop(); 26 // } 27 // private: 28 // void DoStuff() { 29 // // This method is called every second to do stuff. 30 // ... 31 // } 32 // base::RepeatingTimer timer_; 33 // }; 34 // 35 // Both OneShotTimer and RepeatingTimer also support a Reset method, which 36 // allows you to easily defer the timer event until the timer delay passes once 37 // again. So, in the above example, if 0.5 seconds have already passed, 38 // calling Reset on |timer_| would postpone DoStuff by another 1 second. In 39 // other words, Reset is shorthand for calling Stop and then Start again with 40 // the same arguments. 41 // 42 // These APIs are not thread safe. All methods must be called from the same 43 // sequence (not necessarily the construction sequence), except for the 44 // destructor and SetTaskRunner(). 45 // - The destructor may be called from any sequence when the timer is not 46 // running and there is no scheduled task active, i.e. when Start() has never 47 // been called or after AbandonAndStop() has been called. 48 // - SetTaskRunner() may be called from any sequence when the timer is not 49 // running, i.e. when Start() has never been called or Stop() has been called 50 // since the last Start(). 51 // 52 // By default, the scheduled tasks will be run on the same sequence that the 53 // Timer was *started on*, but this can be changed *prior* to Start() via 54 // SetTaskRunner(). 55 56 #ifndef BASE_TIMER_TIMER_H_ 57 #define BASE_TIMER_TIMER_H_ 58 59 // IMPORTANT: If you change timer code, make sure that all tests (including 60 // disabled ones) from timer_unittests.cc pass locally. Some are disabled 61 // because they're flaky on the buildbot, but when you run them locally you 62 // should be able to tell the difference. 63 64 #include <memory> 65 66 #include "base/base_export.h" 67 #include "base/bind.h" 68 #include "base/bind_helpers.h" 69 #include "base/callback.h" 70 #include "base/location.h" 71 #include "base/macros.h" 72 #include "base/sequence_checker_impl.h" 73 #include "base/sequenced_task_runner.h" 74 #include "base/time/time.h" 75 76 namespace base { 77 78 class BaseTimerTaskInternal; 79 class TickClock; 80 81 //----------------------------------------------------------------------------- 82 // This class wraps TaskRunner::PostDelayedTask to manage delayed and repeating 83 // tasks. See meta comment above for thread-safety requirements. 84 // 85 class BASE_EXPORT Timer { 86 public: 87 // Construct a timer in repeating or one-shot mode. Start must be called later 88 // to set task info. |retain_user_task| determines whether the user_task is 89 // retained or reset when it runs or stops. If |tick_clock| is provided, it is 90 // used instead of TimeTicks::Now() to get TimeTicks when scheduling tasks. 91 Timer(bool retain_user_task, bool is_repeating); 92 Timer(bool retain_user_task, bool is_repeating, const TickClock* tick_clock); 93 94 // Construct a timer with retained task info. If |tick_clock| is provided, it 95 // is used instead of TimeTicks::Now() to get TimeTicks when scheduling tasks. 96 Timer(const Location& posted_from, 97 TimeDelta delay, 98 const base::Closure& user_task, 99 bool is_repeating); 100 Timer(const Location& posted_from, 101 TimeDelta delay, 102 const base::Closure& user_task, 103 bool is_repeating, 104 const TickClock* tick_clock); 105 106 virtual ~Timer(); 107 108 // Returns true if the timer is running (i.e., not stopped). 109 bool IsRunning() const; 110 111 // Returns the current delay for this timer. 112 TimeDelta GetCurrentDelay() const; 113 114 // Set the task runner on which the task should be scheduled. This method can 115 // only be called before any tasks have been scheduled. If |task_runner| runs 116 // tasks on a different sequence than the sequence owning this Timer, 117 // |user_task_| will be posted to it when the Timer fires (note that this 118 // means |user_task_| can run after ~Timer() and should support that). 119 virtual void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner); 120 121 // Start the timer to run at the given |delay| from now. If the timer is 122 // already running, it will be replaced to call the given |user_task|. 123 virtual void Start(const Location& posted_from, 124 TimeDelta delay, 125 const base::Closure& user_task); 126 127 // Start the timer to run at the given |delay| from now. If the timer is 128 // already running, it will be replaced to call a task formed from 129 // |reviewer->*method|. 130 template <class Receiver> Start(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)())131 void Start(const Location& posted_from, 132 TimeDelta delay, 133 Receiver* receiver, 134 void (Receiver::*method)()) { 135 Start(posted_from, delay, 136 base::BindRepeating(method, base::Unretained(receiver))); 137 } 138 139 // Call this method to stop and cancel the timer. It is a no-op if the timer 140 // is not running. 141 virtual void Stop(); 142 143 // Stop running task (if any) and abandon scheduled task (if any). AbandonAndStop()144 void AbandonAndStop() { 145 AbandonScheduledTask(); 146 147 Stop(); 148 // No more member accesses here: |this| could be deleted at this point. 149 } 150 151 // Call this method to reset the timer delay. The |user_task_| must be set. If 152 // the timer is not running, this will start it by posting a task. 153 virtual void Reset(); 154 user_task()155 const base::Closure& user_task() const { return user_task_; } desired_run_time()156 const TimeTicks& desired_run_time() const { return desired_run_time_; } 157 158 protected: 159 // Returns the current tick count. 160 TimeTicks Now() const; 161 set_user_task(const Closure & task)162 void set_user_task(const Closure& task) { user_task_ = task; } set_desired_run_time(TimeTicks desired)163 void set_desired_run_time(TimeTicks desired) { desired_run_time_ = desired; } set_is_running(bool running)164 void set_is_running(bool running) { is_running_ = running; } 165 posted_from()166 const Location& posted_from() const { return posted_from_; } 167 168 // The task runner on which the task should be scheduled. If it is null, the 169 // task runner for the current sequence will be used. 170 scoped_refptr<SequencedTaskRunner> task_runner_; 171 172 // Timer isn't thread-safe and must only be used on its origin sequence 173 // (sequence on which it was started). Once fully Stop()'ed it may be 174 // destroyed or restarted on another sequence. 175 SequenceChecker origin_sequence_checker_; 176 177 private: 178 friend class BaseTimerTaskInternal; 179 180 // Allocates a new |scheduled_task_| and posts it on the current sequence with 181 // the given |delay|. |scheduled_task_| must be null. |scheduled_run_time_| 182 // and |desired_run_time_| are reset to Now() + delay. 183 void PostNewScheduledTask(TimeDelta delay); 184 185 // Returns the task runner on which the task should be scheduled. If the 186 // corresponding |task_runner_| field is null, the task runner for the current 187 // sequence is returned. 188 scoped_refptr<SequencedTaskRunner> GetTaskRunner(); 189 190 // Disable |scheduled_task_| and abandon it so that it no longer refers back 191 // to this object. 192 void AbandonScheduledTask(); 193 194 // Called by BaseTimerTaskInternal when the delayed task fires. 195 void RunScheduledTask(); 196 197 // When non-null, the |scheduled_task_| was posted to call RunScheduledTask() 198 // at |scheduled_run_time_|. 199 BaseTimerTaskInternal* scheduled_task_; 200 201 // Location in user code. 202 Location posted_from_; 203 // Delay requested by user. 204 TimeDelta delay_; 205 // |user_task_| is what the user wants to be run at |desired_run_time_|. 206 base::Closure user_task_; 207 208 // The time at which |scheduled_task_| is expected to fire. This time can be a 209 // "zero" TimeTicks if the task must be run immediately. 210 TimeTicks scheduled_run_time_; 211 212 // The desired run time of |user_task_|. The user may update this at any time, 213 // even if their previous request has not run yet. If |desired_run_time_| is 214 // greater than |scheduled_run_time_|, a continuation task will be posted to 215 // wait for the remaining time. This allows us to reuse the pending task so as 216 // not to flood the delayed queues with orphaned tasks when the user code 217 // excessively Stops and Starts the timer. This time can be a "zero" TimeTicks 218 // if the task must be run immediately. 219 TimeTicks desired_run_time_; 220 221 // Repeating timers automatically post the task again before calling the task 222 // callback. 223 const bool is_repeating_; 224 225 // If true, hold on to the |user_task_| closure object for reuse. 226 const bool retain_user_task_; 227 228 // The tick clock used to calculate the run time for scheduled tasks. 229 const TickClock* const tick_clock_; 230 231 // If true, |user_task_| is scheduled to run sometime in the future. 232 bool is_running_; 233 234 DISALLOW_COPY_AND_ASSIGN(Timer); 235 }; 236 237 //----------------------------------------------------------------------------- 238 // A simple, one-shot timer. See usage notes at the top of the file. 239 class BASE_EXPORT OneShotTimer : public Timer { 240 public: OneShotTimer()241 OneShotTimer() : OneShotTimer(nullptr) {} OneShotTimer(const TickClock * tick_clock)242 explicit OneShotTimer(const TickClock* tick_clock) 243 : Timer(false, false, tick_clock) {} 244 245 // Run the scheduled task immediately, and stop the timer. The timer needs to 246 // be running. 247 void FireNow(); 248 }; 249 250 //----------------------------------------------------------------------------- 251 // A simple, repeating timer. See usage notes at the top of the file. 252 class RepeatingTimer : public Timer { 253 public: RepeatingTimer()254 RepeatingTimer() : RepeatingTimer(nullptr) {} RepeatingTimer(const TickClock * tick_clock)255 explicit RepeatingTimer(const TickClock* tick_clock) 256 : Timer(true, true, tick_clock) {} 257 RepeatingTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task)258 RepeatingTimer(const Location& posted_from, 259 TimeDelta delay, 260 RepeatingClosure user_task) 261 : Timer(posted_from, delay, std::move(user_task), true) {} RepeatingTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task,const TickClock * tick_clock)262 RepeatingTimer(const Location& posted_from, 263 TimeDelta delay, 264 RepeatingClosure user_task, 265 const TickClock* tick_clock) 266 : Timer(posted_from, delay, std::move(user_task), true, tick_clock) {} 267 }; 268 269 //----------------------------------------------------------------------------- 270 // A simple, one-shot timer with the retained user task. See usage notes at the 271 // top of the file. 272 class RetainingOneShotTimer : public Timer { 273 public: RetainingOneShotTimer()274 RetainingOneShotTimer() : RetainingOneShotTimer(nullptr) {} RetainingOneShotTimer(const TickClock * tick_clock)275 explicit RetainingOneShotTimer(const TickClock* tick_clock) 276 : Timer(true, false, tick_clock) {} 277 RetainingOneShotTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task)278 RetainingOneShotTimer(const Location& posted_from, 279 TimeDelta delay, 280 RepeatingClosure user_task) 281 : Timer(posted_from, delay, std::move(user_task), false) {} RetainingOneShotTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task,const TickClock * tick_clock)282 RetainingOneShotTimer(const Location& posted_from, 283 TimeDelta delay, 284 RepeatingClosure user_task, 285 const TickClock* tick_clock) 286 : Timer(posted_from, delay, std::move(user_task), false, tick_clock) {} 287 }; 288 289 //----------------------------------------------------------------------------- 290 // A Delay timer is like The Button from Lost. Once started, you have to keep 291 // calling Reset otherwise it will call the given method on the sequence it was 292 // initially Reset() from. 293 // 294 // Once created, it is inactive until Reset is called. Once |delay| seconds have 295 // passed since the last call to Reset, the callback is made. Once the callback 296 // has been made, it's inactive until Reset is called again. 297 // 298 // If destroyed, the timeout is canceled and will not occur even if already 299 // inflight. 300 class DelayTimer { 301 public: 302 template <class Receiver> DelayTimer(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)())303 DelayTimer(const Location& posted_from, 304 TimeDelta delay, 305 Receiver* receiver, 306 void (Receiver::*method)()) 307 : DelayTimer(posted_from, delay, receiver, method, nullptr) {} 308 309 template <class Receiver> DelayTimer(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)(),const TickClock * tick_clock)310 DelayTimer(const Location& posted_from, 311 TimeDelta delay, 312 Receiver* receiver, 313 void (Receiver::*method)(), 314 const TickClock* tick_clock) 315 : timer_(posted_from, 316 delay, 317 BindRepeating(method, Unretained(receiver)), 318 tick_clock) {} 319 Reset()320 void Reset() { timer_.Reset(); } 321 322 private: 323 RetainingOneShotTimer timer_; 324 325 DISALLOW_COPY_AND_ASSIGN(DelayTimer); 326 }; 327 328 } // namespace base 329 330 #endif // BASE_TIMER_TIMER_H_ 331