| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // OneShotTimer, RepeatingTimer and RetainingOneShotTimer provide a simple timer | |
| // API. As the names suggest, OneShotTimer calls you back once after a time | |
| // delay expires. | |
| // RepeatingTimer on the other hand calls you back periodically with the | |
| // prescribed time interval. | |
| // RetainingOneShotTimer doesn't repeat the task itself like OneShotTimer, but | |
| // retains the given task after the time out. You can restart it with Reset | |
| // again without giving new task to Start. | |
| // | |
| // All of OneShotTimer, RepeatingTimer and RetainingOneShotTimer cancel the | |
| // timer when they go out of scope, which makes it easy to ensure that you do | |
| // not get called when your object has gone out of scope. Just instantiate a | |
| // timer as a member variable of the class for which you wish to receive timer | |
| // events. | |
| // | |
| // Sample RepeatingTimer usage: | |
| // | |
| // class MyClass { | |
| // public: | |
| // void StartDoingStuff() { | |
| // timer_.Start(FROM_HERE, TimeDelta::FromSeconds(1), | |
| // this, &MyClass::DoStuff); | |
| // } | |
| // void StopDoingStuff() { | |
| // timer_.Stop(); | |
| // } | |
| // private: | |
| // void DoStuff() { | |
| // // This method is called every second to do stuff. | |
| // ... | |
| // } | |
| // base::RepeatingTimer timer_; | |
| // }; | |
| // | |
| // Timers also support a Reset method, which allows you to easily defer the | |
| // timer event until the timer delay passes once again. So, in the above | |
| // example, if 0.5 seconds have already passed, calling Reset on |timer_| | |
| // would postpone DoStuff by another 1 second. In other words, Reset is | |
| // shorthand for calling Stop and then Start again with the same arguments. | |
| // | |
| // These APIs are not thread safe. All methods must be called from the same | |
| // sequence (not necessarily the construction sequence), except for the | |
| // destructor and SetTaskRunner(). | |
| // - The destructor may be called from any sequence when the timer is not | |
| // running and there is no scheduled task active, i.e. when Start() has never | |
| // been called or after AbandonAndStop() has been called. | |
| // - SetTaskRunner() may be called from any sequence when the timer is not | |
| // running, i.e. when Start() has never been called or Stop() has been called | |
| // since the last Start(). | |
| // | |
| // By default, the scheduled tasks will be run on the same sequence that the | |
| // Timer was *started on*, but this can be changed *prior* to Start() via | |
| // SetTaskRunner(). | |
| #ifndef BASE_TIMER_TIMER_H_ | |
| #define BASE_TIMER_TIMER_H_ | |
| // IMPORTANT: If you change timer code, make sure that all tests (including | |
| // disabled ones) from timer_unittests.cc pass locally. Some are disabled | |
| // because they're flaky on the buildbot, but when you run them locally you | |
| // should be able to tell the difference. | |
| #include <memory> | |
| #include "base/base_export.h" | |
| #include "base/bind.h" | |
| #include "base/bind_helpers.h" | |
| #include "base/callback.h" | |
| #include "base/location.h" | |
| #include "base/macros.h" | |
| #include "base/sequence_checker_impl.h" | |
| #include "base/sequenced_task_runner.h" | |
| #include "base/time/time.h" | |
| namespace base { | |
| class TickClock; | |
| namespace internal { | |
| class BaseTimerTaskInternal; | |
| //----------------------------------------------------------------------------- | |
| // This class wraps TaskRunner::PostDelayedTask to manage delayed and repeating | |
| // tasks. See meta comment above for thread-safety requirements. | |
| // Do not use this class directly. Use one of OneShotTimer, RepeatingTimer or | |
| // RetainingOneShotTimer. | |
| // | |
| class BASE_EXPORT TimerBase { | |
| public: | |
| // Constructs a timer. Start must be called later to set task info. | |
| // If |tick_clock| is provided, it is used instead of TimeTicks::Now() to get | |
| // TimeTicks when scheduling tasks. | |
| TimerBase(); | |
| explicit TimerBase(const TickClock* tick_clock); | |
| // Construct a timer with task info. | |
| // If |tick_clock| is provided, it is used instead of TimeTicks::Now() to get | |
| // TimeTicks when scheduling tasks. | |
| TimerBase(const Location& posted_from, TimeDelta delay); | |
| TimerBase(const Location& posted_from, | |
| TimeDelta delay, | |
| const TickClock* tick_clock); | |
| virtual ~TimerBase(); | |
| // Returns true if the timer is running (i.e., not stopped). | |
| bool IsRunning() const; | |
| // Returns the current delay for this timer. | |
| TimeDelta GetCurrentDelay() const; | |
| // Set the task runner on which the task should be scheduled. This method can | |
| // only be called before any tasks have been scheduled. If |task_runner| runs | |
| // tasks on a different sequence than the sequence owning this Timer, the user | |
| // task will be posted to it when the Timer fires (note that this means the | |
| // user task can run after ~Timer() and should support that). | |
| virtual void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner); | |
| // Call this method to stop and cancel the timer. It is a no-op if the timer | |
| // is not running. | |
| virtual void Stop(); | |
| // Stop running task (if any) and abandon scheduled task (if any). | |
| void AbandonAndStop() { | |
| AbandonScheduledTask(); | |
| Stop(); | |
| // No more member accesses here: |this| could be deleted at this point. | |
| } | |
| // Call this method to reset the timer delay. The user task must be set. If | |
| // the timer is not running, this will start it by posting a task. | |
| virtual void Reset(); | |
| const TimeTicks& desired_run_time() const { return desired_run_time_; } | |
| protected: | |
| virtual void OnStop() = 0; | |
| virtual void RunUserTask() = 0; | |
| // Returns the current tick count. | |
| TimeTicks Now() const; | |
| void set_desired_run_time(TimeTicks desired) { desired_run_time_ = desired; } | |
| void set_is_running(bool running) { is_running_ = running; } | |
| const Location& posted_from() const { return posted_from_; } | |
| // The task runner on which the task should be scheduled. If it is null, the | |
| // task runner for the current sequence will be used. | |
| scoped_refptr<SequencedTaskRunner> task_runner_; | |
| // Timer isn't thread-safe and must only be used on its origin sequence | |
| // (sequence on which it was started). Once fully Stop()'ed it may be | |
| // destroyed or restarted on another sequence. | |
| SequenceChecker origin_sequence_checker_; | |
| // Allocates a new |scheduled_task_| and posts it on the current sequence with | |
| // the given |delay|. |scheduled_task_| must be null. |scheduled_run_time_| | |
| // and |desired_run_time_| are reset to Now() + delay. | |
| void PostNewScheduledTask(TimeDelta delay); | |
| void StartInternal(const Location& posted_from, TimeDelta delay); | |
| private: | |
| friend class BaseTimerTaskInternal; | |
| // Returns the task runner on which the task should be scheduled. If the | |
| // corresponding |task_runner_| field is null, the task runner for the current | |
| // sequence is returned. | |
| scoped_refptr<SequencedTaskRunner> GetTaskRunner(); | |
| // Disable |scheduled_task_| and abandon it so that it no longer refers back | |
| // to this object. | |
| void AbandonScheduledTask(); | |
| // Called by BaseTimerTaskInternal when the delayed task fires. | |
| void RunScheduledTask(); | |
| // When non-null, the |scheduled_task_| was posted to call RunScheduledTask() | |
| // at |scheduled_run_time_|. | |
| BaseTimerTaskInternal* scheduled_task_; | |
| // Location in user code. | |
| Location posted_from_; | |
| // Delay requested by user. | |
| TimeDelta delay_; | |
| // The time at which |scheduled_task_| is expected to fire. This time can be a | |
| // "zero" TimeTicks if the task must be run immediately. | |
| TimeTicks scheduled_run_time_; | |
| // The desired run time of |user_task_|. The user may update this at any time, | |
| // even if their previous request has not run yet. If |desired_run_time_| is | |
| // greater than |scheduled_run_time_|, a continuation task will be posted to | |
| // wait for the remaining time. This allows us to reuse the pending task so as | |
| // not to flood the delayed queues with orphaned tasks when the user code | |
| // excessively Stops and Starts the timer. This time can be a "zero" TimeTicks | |
| // if the task must be run immediately. | |
| TimeTicks desired_run_time_; | |
| // The tick clock used to calculate the run time for scheduled tasks. | |
| const TickClock* const tick_clock_; | |
| // If true, |user_task_| is scheduled to run sometime in the future. | |
| bool is_running_; | |
| DISALLOW_COPY_AND_ASSIGN(TimerBase); | |
| }; | |
| } // namespace internal | |
| //----------------------------------------------------------------------------- | |
| // A simple, one-shot timer. See usage notes at the top of the file. | |
| class BASE_EXPORT OneShotTimer : public internal::TimerBase { | |
| public: | |
| OneShotTimer(); | |
| explicit OneShotTimer(const TickClock* tick_clock); | |
| ~OneShotTimer() override; | |
| // Start the timer to run at the given |delay| from now. If the timer is | |
| // already running, it will be replaced to call the given |user_task|. | |
| virtual void Start(const Location& posted_from, | |
| TimeDelta delay, | |
| OnceClosure user_task); | |
| // Start the timer to run at the given |delay| from now. If the timer is | |
| // already running, it will be replaced to call a task formed from | |
| // |reviewer->*method|. | |
| template <class Receiver> | |
| void Start(const Location& posted_from, | |
| TimeDelta delay, | |
| Receiver* receiver, | |
| void (Receiver::*method)()) { | |
| Start(posted_from, delay, BindOnce(method, Unretained(receiver))); | |
| } | |
| // Run the scheduled task immediately, and stop the timer. The timer needs to | |
| // be running. | |
| void FireNow(); | |
| private: | |
| void OnStop() final; | |
| void RunUserTask() final; | |
| OnceClosure user_task_; | |
| DISALLOW_COPY_AND_ASSIGN(OneShotTimer); | |
| }; | |
| //----------------------------------------------------------------------------- | |
| // A simple, repeating timer. See usage notes at the top of the file. | |
| class BASE_EXPORT RepeatingTimer : public internal::TimerBase { | |
| public: | |
| RepeatingTimer(); | |
| explicit RepeatingTimer(const TickClock* tick_clock); | |
| ~RepeatingTimer() override; | |
| RepeatingTimer(const Location& posted_from, | |
| TimeDelta delay, | |
| RepeatingClosure user_task); | |
| RepeatingTimer(const Location& posted_from, | |
| TimeDelta delay, | |
| RepeatingClosure user_task, | |
| const TickClock* tick_clock); | |
| // Start the timer to run at the given |delay| from now. If the timer is | |
| // already running, it will be replaced to call the given |user_task|. | |
| virtual void Start(const Location& posted_from, | |
| TimeDelta delay, | |
| RepeatingClosure user_task); | |
| // Start the timer to run at the given |delay| from now. If the timer is | |
| // already running, it will be replaced to call a task formed from | |
| // |reviewer->*method|. | |
| template <class Receiver> | |
| void Start(const Location& posted_from, | |
| TimeDelta delay, | |
| Receiver* receiver, | |
| void (Receiver::*method)()) { | |
| Start(posted_from, delay, BindRepeating(method, Unretained(receiver))); | |
| } | |
| const RepeatingClosure& user_task() const { return user_task_; } | |
| private: | |
| // Mark this final, so that the destructor can call this safely. | |
| void OnStop() final; | |
| void RunUserTask() override; | |
| RepeatingClosure user_task_; | |
| DISALLOW_COPY_AND_ASSIGN(RepeatingTimer); | |
| }; | |
| //----------------------------------------------------------------------------- | |
| // A simple, one-shot timer with the retained user task. See usage notes at the | |
| // top of the file. | |
| class BASE_EXPORT RetainingOneShotTimer : public internal::TimerBase { | |
| public: | |
| RetainingOneShotTimer(); | |
| explicit RetainingOneShotTimer(const TickClock* tick_clock); | |
| ~RetainingOneShotTimer() override; | |
| RetainingOneShotTimer(const Location& posted_from, | |
| TimeDelta delay, | |
| RepeatingClosure user_task); | |
| RetainingOneShotTimer(const Location& posted_from, | |
| TimeDelta delay, | |
| RepeatingClosure user_task, | |
| const TickClock* tick_clock); | |
| // Start the timer to run at the given |delay| from now. If the timer is | |
| // already running, it will be replaced to call the given |user_task|. | |
| virtual void Start(const Location& posted_from, | |
| TimeDelta delay, | |
| RepeatingClosure user_task); | |
| // Start the timer to run at the given |delay| from now. If the timer is | |
| // already running, it will be replaced to call a task formed from | |
| // |reviewer->*method|. | |
| template <class Receiver> | |
| void Start(const Location& posted_from, | |
| TimeDelta delay, | |
| Receiver* receiver, | |
| void (Receiver::*method)()) { | |
| Start(posted_from, delay, BindRepeating(method, Unretained(receiver))); | |
| } | |
| const RepeatingClosure& user_task() const { return user_task_; } | |
| protected: | |
| void set_user_task(const RepeatingClosure& task) { user_task_ = task; } | |
| private: | |
| // Mark this final, so that the destructor can call this safely. | |
| void OnStop() final; | |
| void RunUserTask() override; | |
| RepeatingClosure user_task_; | |
| DISALLOW_COPY_AND_ASSIGN(RetainingOneShotTimer); | |
| }; | |
| //----------------------------------------------------------------------------- | |
| // A Delay timer is like The Button from Lost. Once started, you have to keep | |
| // calling Reset otherwise it will call the given method on the sequence it was | |
| // initially Reset() from. | |
| // | |
| // Once created, it is inactive until Reset is called. Once |delay| seconds have | |
| // passed since the last call to Reset, the callback is made. Once the callback | |
| // has been made, it's inactive until Reset is called again. | |
| // | |
| // If destroyed, the timeout is canceled and will not occur even if already | |
| // inflight. | |
| class DelayTimer { | |
| public: | |
| template <class Receiver> | |
| DelayTimer(const Location& posted_from, | |
| TimeDelta delay, | |
| Receiver* receiver, | |
| void (Receiver::*method)()) | |
| : DelayTimer(posted_from, delay, receiver, method, nullptr) {} | |
| template <class Receiver> | |
| DelayTimer(const Location& posted_from, | |
| TimeDelta delay, | |
| Receiver* receiver, | |
| void (Receiver::*method)(), | |
| const TickClock* tick_clock) | |
| : timer_(posted_from, | |
| delay, | |
| BindRepeating(method, Unretained(receiver)), | |
| tick_clock) {} | |
| void Reset() { timer_.Reset(); } | |
| private: | |
| RetainingOneShotTimer timer_; | |
| DISALLOW_COPY_AND_ASSIGN(DelayTimer); | |
| }; | |
| } // namespace base | |
| #endif // BASE_TIMER_TIMER_H_ |