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<MyClass> 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// NOTE: These APIs are not thread safe. Always call from the same thread.
43
44#ifndef BASE_TIMER_TIMER_H_
45#define BASE_TIMER_TIMER_H_
46
47// IMPORTANT: If you change timer code, make sure that all tests (including
48// disabled ones) from timer_unittests.cc pass locally. Some are disabled
49// because they're flaky on the buildbot, but when you run them locally you
50// should be able to tell the difference.
51
52#include "base/base_export.h"
53#include "base/basictypes.h"
54#include "base/bind.h"
55#include "base/bind_helpers.h"
56#include "base/callback.h"
57#include "base/location.h"
58#include "base/time/time.h"
59
60namespace base {
61
62class BaseTimerTaskInternal;
63
64//-----------------------------------------------------------------------------
65// This class wraps MessageLoop::PostDelayedTask to manage delayed and repeating
66// tasks. It must be destructed on the same thread that starts tasks. There are
67// DCHECKs in place to verify this.
68//
69class BASE_EXPORT Timer {
70 public:
71  // Construct a timer in repeating or one-shot mode. Start or SetTaskInfo must
72  // be called later to set task info. |retain_user_task| determines whether the
73  // user_task is retained or reset when it runs or stops.
74  Timer(bool retain_user_task, bool is_repeating);
75
76  // Construct a timer with retained task info.
77  Timer(const tracked_objects::Location& posted_from,
78        TimeDelta delay,
79        const base::Closure& user_task,
80        bool is_repeating);
81
82  virtual ~Timer();
83
84  // Returns true if the timer is running (i.e., not stopped).
85  virtual bool IsRunning() const;
86
87  // Returns the current delay for this timer.
88  virtual TimeDelta GetCurrentDelay() const;
89
90  // Start the timer to run at the given |delay| from now. If the timer is
91  // already running, it will be replaced to call the given |user_task|.
92  virtual void Start(const tracked_objects::Location& posted_from,
93                     TimeDelta delay,
94                     const base::Closure& user_task);
95
96  // Call this method to stop and cancel the timer.  It is a no-op if the timer
97  // is not running.
98  virtual void Stop();
99
100  // Call this method to reset the timer delay. The user_task_ must be set. If
101  // the timer is not running, this will start it by posting a task.
102  virtual void Reset();
103
104  const base::Closure& user_task() const { return user_task_; }
105  const TimeTicks& desired_run_time() const { return desired_run_time_; }
106
107 protected:
108  // Used to initiate a new delayed task.  This has the side-effect of disabling
109  // scheduled_task_ if it is non-null.
110  void SetTaskInfo(const tracked_objects::Location& posted_from,
111                   TimeDelta delay,
112                   const base::Closure& user_task);
113
114  bool retain_user_task() const { return retain_user_task_; }
115  bool is_repeating() const { return is_repeating_; }
116
117 private:
118  friend class BaseTimerTaskInternal;
119
120  // Allocates a new scheduled_task_ and posts it on the current MessageLoop
121  // with the given |delay|. scheduled_task_ must be NULL. scheduled_run_time_
122  // and desired_run_time_ are reset to Now() + delay.
123  void PostNewScheduledTask(TimeDelta delay);
124
125  // Disable scheduled_task_ and abandon it so that it no longer refers back to
126  // this object.
127  void AbandonScheduledTask();
128
129  // Called by BaseTimerTaskInternal when the MessageLoop runs it.
130  void RunScheduledTask();
131
132  // Stop running task (if any) and abandon scheduled task (if any).
133  void StopAndAbandon() {
134    Stop();
135    AbandonScheduledTask();
136  }
137
138  // When non-NULL, the scheduled_task_ is waiting in the MessageLoop to call
139  // RunScheduledTask() at scheduled_run_time_.
140  BaseTimerTaskInternal* scheduled_task_;
141
142  // Location in user code.
143  tracked_objects::Location posted_from_;
144  // Delay requested by user.
145  TimeDelta delay_;
146  // user_task_ is what the user wants to be run at desired_run_time_.
147  base::Closure user_task_;
148
149  // The estimated time that the MessageLoop will run the scheduled_task_ that
150  // will call RunScheduledTask(). This time can be a "zero" TimeTicks if the
151  // task must be run immediately.
152  TimeTicks scheduled_run_time_;
153
154  // The desired run time of user_task_. The user may update this at any time,
155  // even if their previous request has not run yet. If desired_run_time_ is
156  // greater than scheduled_run_time_, a continuation task will be posted to
157  // wait for the remaining time. This allows us to reuse the pending task so as
158  // not to flood the MessageLoop with orphaned tasks when the user code
159  // excessively Stops and Starts the timer. This time can be a "zero" TimeTicks
160  // if the task must be run immediately.
161  TimeTicks desired_run_time_;
162
163  // Thread ID of current MessageLoop for verifying single-threaded usage.
164  int thread_id_;
165
166  // Repeating timers automatically post the task again before calling the task
167  // callback.
168  const bool is_repeating_;
169
170  // If true, hold on to the user_task_ closure object for reuse.
171  const bool retain_user_task_;
172
173  // If true, user_task_ is scheduled to run sometime in the future.
174  bool is_running_;
175
176  DISALLOW_COPY_AND_ASSIGN(Timer);
177};
178
179//-----------------------------------------------------------------------------
180// This class is an implementation detail of OneShotTimer and RepeatingTimer.
181// Please do not use this class directly.
182template <class Receiver, bool kIsRepeating>
183class BaseTimerMethodPointer : public Timer {
184 public:
185  typedef void (Receiver::*ReceiverMethod)();
186
187  // This is here to work around the fact that Timer::Start is "hidden" by the
188  // Start definition below, rather than being overloaded.
189  // TODO(tim): We should remove uses of BaseTimerMethodPointer::Start below
190  // and convert callers to use the base::Closure version in Timer::Start,
191  // see bug 148832.
192  using Timer::Start;
193
194  BaseTimerMethodPointer() : Timer(kIsRepeating, kIsRepeating) {}
195
196  // Start the timer to run at the given |delay| from now. If the timer is
197  // already running, it will be replaced to call a task formed from
198  // |reviewer->*method|.
199  virtual void Start(const tracked_objects::Location& posted_from,
200                     TimeDelta delay,
201                     Receiver* receiver,
202                     ReceiverMethod method) {
203    Timer::Start(posted_from, delay,
204                 base::Bind(method, base::Unretained(receiver)));
205  }
206};
207
208//-----------------------------------------------------------------------------
209// A simple, one-shot timer.  See usage notes at the top of the file.
210template <class Receiver>
211class OneShotTimer : public BaseTimerMethodPointer<Receiver, false> {};
212
213//-----------------------------------------------------------------------------
214// A simple, repeating timer.  See usage notes at the top of the file.
215template <class Receiver>
216class RepeatingTimer : public BaseTimerMethodPointer<Receiver, true> {};
217
218//-----------------------------------------------------------------------------
219// A Delay timer is like The Button from Lost. Once started, you have to keep
220// calling Reset otherwise it will call the given method in the MessageLoop
221// thread.
222//
223// Once created, it is inactive until Reset is called. Once |delay| seconds have
224// passed since the last call to Reset, the callback is made. Once the callback
225// has been made, it's inactive until Reset is called again.
226//
227// If destroyed, the timeout is canceled and will not occur even if already
228// inflight.
229template <class Receiver>
230class DelayTimer : protected Timer {
231 public:
232  typedef void (Receiver::*ReceiverMethod)();
233
234  DelayTimer(const tracked_objects::Location& posted_from,
235             TimeDelta delay,
236             Receiver* receiver,
237             ReceiverMethod method)
238      : Timer(posted_from, delay,
239              base::Bind(method, base::Unretained(receiver)),
240              false) {}
241
242  void Reset() { Timer::Reset(); }
243};
244
245}  // namespace base
246
247#endif  // BASE_TIMER_TIMER_H_
248