• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // A "timer" takes care of invoking a callback in the future, once or
6 // repeatedly. The callback is invoked:
7 // - OneShotTimer: Once after a `TimeDelta` delay has elapsed.
8 // - RetainingOneShotTimer: Same as OneShotTimer, but the callback is retained
9 //    after being executed, allowing another invocation to be scheduled with
10 //    Reset() without specifying the callback again.
11 // - DeadlineTimer: Once at the specified `TimeTicks` time.
12 // - RepeatingTimer: Repeatedly, with a specified `TimeDelta` delay before the
13 //    first invocation and between invocations.
14 // - MetronomeTimer: Repeatedly, with a specified `TimeDelta` delay between the
15 //    beginning of each invocations such that a constant phase is respected.
16 // (Retaining)OneShotTimer and RepeatingTimer automatically apply some leeway to
17 // the delay whereas DeadlineTimer and MetronomeTimer allow more control over
18 // the requested time. As a result, the former are generally more
19 // power-efficient.
20 // Prefer using (Retaining)OneShotTimer and RepeatingTimer because they
21 // automatically apply some leeway to the delay which enables power-efficient
22 // scheduling.
23 
24 // Scheduled invocations can be cancelled with Stop() or by deleting the
25 // Timer. The latter makes it easy to ensure that an object is not accessed by a
26 // Timer after it has been deleted: just make the Timer a member of the object
27 // which receives Timer events (see example below).
28 //
29 // Sample RepeatingTimer usage:
30 //
31 //   class MyClass {
32 //    public:
33 //     void StartDoingStuff() {
34 //       timer_.Start(FROM_HERE, base::Seconds(1),
35 //                    this, &MyClass::DoStuff);
36 //       // Alternative form if the callback is not bound to `this` or
37 //       // requires arguments:
38 //       //    timer_.Start(FROM_HERE, base::Seconds(1),
39 //       //                 base::BindRepeating(&MyFunction, 42));
40 //     }
41 //     void StopDoingStuff() {
42 //       timer_.Stop();
43 //     }
44 //    private:
45 //     void DoStuff() {
46 //       // This method is called every second to do stuff.
47 //       ...
48 //     }
49 //     base::RepeatingTimer timer_;
50 //   };
51 //
52 // These APIs are not thread safe. When a method is called (except the
53 // constructor), all further method calls must be on the same sequence until
54 // Stop(). Once stopped, it may be destroyed or restarted on another sequence.
55 //
56 // By default, the scheduled tasks will be run on the same sequence that the
57 // Timer was *started on*. To mock time in unit tests, some old tests used
58 // SetTaskRunner() to schedule the delay on a test-controlled TaskRunner. The
59 // modern and preferred approach to mock time is to use TaskEnvironment's
60 // MOCK_TIME mode.
61 
62 #ifndef BASE_TIMER_TIMER_H_
63 #define BASE_TIMER_TIMER_H_
64 
65 // IMPORTANT: If you change timer code, make sure that all tests (including
66 // disabled ones) from timer_unittests.cc pass locally. Some are disabled
67 // because they're flaky on the buildbot, but when you run them locally you
68 // should be able to tell the difference.
69 
70 #include "base/base_export.h"
71 #include "base/compiler_specific.h"
72 #include "base/functional/bind.h"
73 #include "base/functional/callback.h"
74 #include "base/functional/callback_helpers.h"
75 #include "base/location.h"
76 #include "base/memory/raw_ptr.h"
77 #include "base/sequence_checker.h"
78 #include "base/task/delayed_task_handle.h"
79 #include "base/task/sequenced_task_runner.h"
80 #include "base/time/time.h"
81 #include "base/types/strong_alias.h"
82 
83 namespace base {
84 
85 class TickClock;
86 
87 namespace internal {
88 
89 // This class wraps logic shared by all timers.
90 class BASE_EXPORT TimerBase {
91  public:
92   TimerBase(const TimerBase&) = delete;
93   TimerBase& operator=(const TimerBase&) = delete;
94 
95   virtual ~TimerBase();
96 
97   // Returns true if the timer is running (i.e., not stopped).
98   bool IsRunning() const;
99 
100   // Sets the task runner on which the delayed task should be scheduled when
101   // this Timer is running. This method can only be called while this Timer
102   // isn't running. If this is used to mock time in tests, the modern and
103   // preferred approach is to use TaskEnvironment::TimeSource::MOCK_TIME. To
104   // avoid racy usage of Timer, |task_runner| must run tasks on the same
105   // sequence which this Timer is bound to (started from). TODO(gab): Migrate
106   // callers using this as a test seam to
107   // TaskEnvironment::TimeSource::MOCK_TIME.
108   virtual void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner);
109 
110   // Call this method to stop the timer and cancel all previously scheduled
111   // tasks. It is a no-op if the timer is not running.
112   virtual void Stop();
113 
114  protected:
115   // Constructs a timer. Start must be called later to set task info.
116   explicit TimerBase(const Location& posted_from = Location());
117 
118   virtual void OnStop() = 0;
119 
120   // Disables the scheduled task and abandons it so that it no longer refers
121   // back to this object.
122   void AbandonScheduledTask();
123 
124   // Returns the task runner on which the task should be scheduled. If the
125   // corresponding |task_runner_| field is null, the task runner for the current
126   // sequence is returned.
127   scoped_refptr<SequencedTaskRunner> GetTaskRunner();
128 
129   // The task runner on which the task should be scheduled. If it is null, the
130   // task runner for the current sequence will be used.
131   scoped_refptr<SequencedTaskRunner> task_runner_;
132 
133   // Timer isn't thread-safe and while it is running, it must only be used on
134   // the same sequence until fully Stop()'ed. Once stopped, it may be destroyed
135   // or restarted on another sequence.
136   SEQUENCE_CHECKER(sequence_checker_);
137 
138   // Location in user code.
139   Location posted_from_ GUARDED_BY_CONTEXT(sequence_checker_);
140 
141   // The handle to the posted delayed task.
142   DelayedTaskHandle delayed_task_handle_ GUARDED_BY_CONTEXT(sequence_checker_);
143 
144   // Callback invoked when the timer is ready. This is saved as a member to
145   // avoid rebinding every time the Timer fires. Lazy initialized the first time
146   // the Timer is started.
147   RepeatingClosure timer_callback_;
148 };
149 
150 //-----------------------------------------------------------------------------
151 // This class wraps logic shared by (Retaining)OneShotTimer and RepeatingTimer.
152 class BASE_EXPORT DelayTimerBase : public TimerBase {
153  public:
154   DelayTimerBase(const DelayTimerBase&) = delete;
155   DelayTimerBase& operator=(const DelayTimerBase&) = delete;
156 
157   ~DelayTimerBase() override;
158 
159   // Returns the current delay for this timer.
160   TimeDelta GetCurrentDelay() const;
161 
162   // Call this method to reset the timer delay. The user task must be set. If
163   // the timer is not running, this will start it by posting a task.
164   virtual void Reset();
165 
desired_run_time()166   TimeTicks desired_run_time() const {
167     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
168     return desired_run_time_;
169   }
170 
171  protected:
172   // Constructs a timer. Start must be called later to set task info.
173   // If |tick_clock| is provided, it is used instead of TimeTicks::Now() to get
174   // TimeTicks when scheduling tasks.
175   explicit DelayTimerBase(const TickClock* tick_clock = nullptr);
176 
177   // Construct a timer with task info.
178   // If |tick_clock| is provided, it is used instead of TimeTicks::Now() to get
179   // TimeTicks when scheduling tasks.
180   DelayTimerBase(const Location& posted_from,
181                  TimeDelta delay,
182                  const TickClock* tick_clock = nullptr);
183 
184   virtual void RunUserTask() = 0;
185 
186   // Schedules |OnScheduledTaskInvoked()| to run on the current sequence with
187   // the given |delay|. |desired_run_time_| is reset to Now() + delay.
188   void ScheduleNewTask(TimeDelta delay);
189 
190   void StartInternal(const Location& posted_from, TimeDelta delay);
191 
192  private:
193   // DCHECKs that the user task is not null. Used to diagnose a recurring bug
194   // where Reset() is called on a OneShotTimer that has already fired.
195   virtual void EnsureNonNullUserTask() = 0;
196 
197   // Returns the current tick count.
198   TimeTicks Now() const;
199 
200   // Called when the scheduled task is invoked. Will run the  |user_task| if the
201   // timer is still running and |desired_run_time_| was reached.
202   void OnScheduledTaskInvoked();
203 
204   // Delay requested by user.
205   TimeDelta delay_ GUARDED_BY_CONTEXT(sequence_checker_);
206 
207   // The desired run time of |user_task_|. The user may update this at any time,
208   // even if their previous request has not run yet. This time can be a "zero"
209   // TimeTicks if the task must be run immediately.
210   TimeTicks desired_run_time_ GUARDED_BY_CONTEXT(sequence_checker_);
211 
212   // The tick clock used to calculate the run time for scheduled tasks.
213   const raw_ptr<const TickClock> tick_clock_
214       GUARDED_BY_CONTEXT(sequence_checker_);
215 };
216 
217 }  // namespace internal
218 
219 //-----------------------------------------------------------------------------
220 // A simple, one-shot timer.  See usage notes at the top of the file.
221 class BASE_EXPORT OneShotTimer : public internal::DelayTimerBase {
222  public:
223   OneShotTimer();
224   explicit OneShotTimer(const TickClock* tick_clock);
225 
226   OneShotTimer(const OneShotTimer&) = delete;
227   OneShotTimer& operator=(const OneShotTimer&) = delete;
228 
229   ~OneShotTimer() override;
230 
231   // Start the timer to run at the given |delay| from now. If the timer is
232   // already running, it will be replaced to call the given |user_task|.
233   virtual void Start(const Location& posted_from,
234                      TimeDelta delay,
235                      OnceClosure user_task);
236 
237   // Start the timer to run at the given |delay| from now. If the timer is
238   // already running, it will be replaced to call a task formed from
239   // |receiver->*method|.
240   template <class Receiver>
Start(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)())241   void Start(const Location& posted_from,
242              TimeDelta delay,
243              Receiver* receiver,
244              void (Receiver::*method)()) {
245     Start(posted_from, delay, BindOnce(method, Unretained(receiver)));
246   }
247 
248   // Run the scheduled task immediately, and stop the timer. The timer needs to
249   // be running.
250   virtual void FireNow();
251 
252  private:
253   void OnStop() final;
254   void RunUserTask() final;
255   void EnsureNonNullUserTask() final;
256 
257   OnceClosure user_task_;
258 };
259 
260 //-----------------------------------------------------------------------------
261 // A simple, repeating timer.  See usage notes at the top of the file.
262 class BASE_EXPORT RepeatingTimer : public internal::DelayTimerBase {
263  public:
264   RepeatingTimer();
265   explicit RepeatingTimer(const TickClock* tick_clock);
266 
267   RepeatingTimer(const RepeatingTimer&) = delete;
268   RepeatingTimer& operator=(const RepeatingTimer&) = delete;
269 
270   ~RepeatingTimer() override;
271 
272   RepeatingTimer(const Location& posted_from,
273                  TimeDelta delay,
274                  RepeatingClosure user_task);
275   RepeatingTimer(const Location& posted_from,
276                  TimeDelta delay,
277                  RepeatingClosure user_task,
278                  const TickClock* tick_clock);
279 
280   // Start the timer to run at the given |delay| from now. If the timer is
281   // already running, it will be replaced to call the given |user_task|.
282   virtual void Start(const Location& posted_from,
283                      TimeDelta delay,
284                      RepeatingClosure user_task);
285 
286   // Start the timer to run at the given |delay| from now. If the timer is
287   // already running, it will be replaced to call a task formed from
288   // |receiver->*method|.
289   template <class Receiver>
Start(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)())290   void Start(const Location& posted_from,
291              TimeDelta delay,
292              Receiver* receiver,
293              void (Receiver::*method)()) {
294     Start(posted_from, delay, BindRepeating(method, Unretained(receiver)));
295   }
296 
user_task()297   const RepeatingClosure& user_task() const LIFETIME_BOUND {
298     return user_task_;
299   }
300 
301  private:
302   // Mark this final, so that the destructor can call this safely.
303   void OnStop() final;
304   void RunUserTask() override;
305   void EnsureNonNullUserTask() final;
306 
307   RepeatingClosure user_task_;
308 };
309 
310 //-----------------------------------------------------------------------------
311 // A simple, one-shot timer with the retained |user_task| which is reused when
312 // Reset() is invoked. See usage notes at the top of the file.
313 class BASE_EXPORT RetainingOneShotTimer : public internal::DelayTimerBase {
314  public:
315   RetainingOneShotTimer();
316   explicit RetainingOneShotTimer(const TickClock* tick_clock);
317 
318   RetainingOneShotTimer(const RetainingOneShotTimer&) = delete;
319   RetainingOneShotTimer& operator=(const RetainingOneShotTimer&) = delete;
320 
321   ~RetainingOneShotTimer() override;
322 
323   RetainingOneShotTimer(const Location& posted_from,
324                         TimeDelta delay,
325                         RepeatingClosure user_task);
326   RetainingOneShotTimer(const Location& posted_from,
327                         TimeDelta delay,
328                         RepeatingClosure user_task,
329                         const TickClock* tick_clock);
330 
331   // Start the timer to run at the given |delay| from now. If the timer is
332   // already running, it will be replaced to call the given |user_task|.
333   virtual void Start(const Location& posted_from,
334                      TimeDelta delay,
335                      RepeatingClosure user_task);
336 
337   // Start the timer to run at the given |delay| from now. If the timer is
338   // already running, it will be replaced to call a task formed from
339   // |receiver->*method|.
340   template <class Receiver>
Start(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)())341   void Start(const Location& posted_from,
342              TimeDelta delay,
343              Receiver* receiver,
344              void (Receiver::*method)()) {
345     Start(posted_from, delay, BindRepeating(method, Unretained(receiver)));
346   }
347 
user_task()348   const RepeatingClosure& user_task() const LIFETIME_BOUND {
349     return user_task_;
350   }
351 
352  private:
353   // Mark this final, so that the destructor can call this safely.
354   void OnStop() final;
355   void RunUserTask() override;
356   void EnsureNonNullUserTask() final;
357 
358   RepeatingClosure user_task_;
359 };
360 
361 //-----------------------------------------------------------------------------
362 // A Delay timer is like The Button from Lost. Once started, you have to keep
363 // calling Reset otherwise it will call the given method on the sequence it was
364 // initially Reset() from.
365 //
366 // Once created, it is inactive until Reset is called. Once |delay| seconds have
367 // passed since the last call to Reset, the callback is made. Once the callback
368 // has been made, it's inactive until Reset is called again.
369 //
370 // If destroyed, the timeout is canceled and will not occur even if already
371 // inflight.
372 class DelayTimer {
373  public:
374   template <class Receiver>
DelayTimer(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)())375   DelayTimer(const Location& posted_from,
376              TimeDelta delay,
377              Receiver* receiver,
378              void (Receiver::*method)())
379       : DelayTimer(posted_from, delay, receiver, method, nullptr) {}
380 
381   template <class Receiver>
DelayTimer(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)(),const TickClock * tick_clock)382   DelayTimer(const Location& posted_from,
383              TimeDelta delay,
384              Receiver* receiver,
385              void (Receiver::*method)(),
386              const TickClock* tick_clock)
387       : timer_(posted_from,
388                delay,
389                BindRepeating(method, Unretained(receiver)),
390                tick_clock) {}
391 
392   DelayTimer(const DelayTimer&) = delete;
393   DelayTimer& operator=(const DelayTimer&) = delete;
394 
Reset()395   void Reset() { timer_.Reset(); }
396 
397  private:
398   RetainingOneShotTimer timer_;
399 };
400 
401 //-----------------------------------------------------------------------------
402 // A one-shot timer that attempts to run |user_task| some time near specified
403 // deadline. See usage notes at the top of the file.
404 class BASE_EXPORT DeadlineTimer : public internal::TimerBase {
405  public:
406   DeadlineTimer();
407   ~DeadlineTimer() override;
408 
409   DeadlineTimer(const DeadlineTimer&) = delete;
410   DeadlineTimer& operator=(const DeadlineTimer&) = delete;
411 
412   // Start the timer to run |user_task| near the specified |deadline| following
413   // |delay_policy| If the timer is already running, it will be replaced to call
414   // the given |user_task|.
415   void Start(const Location& posted_from,
416              TimeTicks deadline,
417              OnceClosure user_task,
418              subtle::DelayPolicy delay_policy =
419                  subtle::DelayPolicy::kFlexiblePreferEarly);
420 
421   // Start the timer to run |user_task| near the specified |deadline|. If the
422   // timer is already running, it will be replaced to call a task formed from
423   // |receiver->*method|.
424   template <class Receiver>
425   void Start(const Location& posted_from,
426              TimeTicks deadline,
427              Receiver* receiver,
428              void (Receiver::*method)(),
429              subtle::DelayPolicy delay_policy =
430                  subtle::DelayPolicy::kFlexiblePreferEarly) {
431     Start(posted_from, deadline, BindOnce(method, Unretained(receiver)),
432           delay_policy);
433   }
434 
435  protected:
436   void OnStop() override;
437 
438   // Schedules |OnScheduledTaskInvoked()| to run on the current sequence at
439   // the given |deadline|.
440   void ScheduleNewTask(TimeTicks deadline, subtle::DelayPolicy delay_policy);
441 
442  private:
443   // Called when the scheduled task is invoked to run the |user_task|.
444   void OnScheduledTaskInvoked();
445 
446   OnceClosure user_task_;
447 };
448 
449 //-----------------------------------------------------------------------------
450 // Repeatedly invokes a callback, waiting for a precise delay between the
451 // beginning of each invocation. See usage notes at the top of the file.
452 class BASE_EXPORT MetronomeTimer : public internal::TimerBase {
453  public:
454   MetronomeTimer();
455   ~MetronomeTimer() override;
456 
457   MetronomeTimer(const MetronomeTimer&) = delete;
458   MetronomeTimer& operator=(const MetronomeTimer&) = delete;
459 
460   MetronomeTimer(const Location& posted_from,
461                  TimeDelta interval,
462                  RepeatingClosure user_task,
463                  TimeTicks phase = TimeTicks());
464 
465   // Start the timer to repeatedly run |user_task| at the specified |interval|;
466   // If not specified, the phase is up to the scheduler, otherwise each
467   // invocation starts as close as possible to `phase + n * delay` for some
468   // integer n. If the timer is already running, it will be replaced to call the
469   // given |user_task|.
470   void Start(const Location& posted_from,
471              TimeDelta interval,
472              RepeatingClosure user_task,
473              TimeTicks phase = TimeTicks());
474 
475   // Same as the previous overload, except that the user task is specified by
476   // `receiver` and `method`.
477   template <class Receiver>
478   void Start(const Location& posted_from,
479              TimeDelta interval,
480              Receiver* receiver,
481              void (Receiver::*method)(),
482              TimeTicks phase = TimeTicks()) {
483     Start(posted_from, interval, BindRepeating(method, Unretained(receiver)),
484           phase);
485   }
486 
487   // Call this method to reset the timer delay. The user task must be set. If
488   // the timer is not running, this will start it by posting a task.
489   void Reset();
490 
491  protected:
492   void OnStop() override;
493 
494   // Schedules |OnScheduledTaskInvoked()| to run on the current sequence at
495   // the next tick.
496   void ScheduleNewTask();
497 
498  private:
499   // Called when the scheduled task is invoked to run the |user_task|.
500   void OnScheduledTaskInvoked();
501 
502   TimeDelta interval_;
503   RepeatingClosure user_task_;
504   TimeTicks phase_;
505 };
506 
507 }  // namespace base
508 
509 #endif  // BASE_TIMER_TIMER_H_
510