xref: /aosp_15_r20/external/cronet/base/timer/timer.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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/functional/bind.h"
72 #include "base/functional/callback.h"
73 #include "base/functional/callback_helpers.h"
74 #include "base/location.h"
75 #include "base/memory/raw_ptr.h"
76 #include "base/sequence_checker.h"
77 #include "base/task/delayed_task_handle.h"
78 #include "base/task/sequenced_task_runner.h"
79 #include "base/time/time.h"
80 #include "base/types/strong_alias.h"
81 
82 namespace base {
83 
84 class TickClock;
85 
86 namespace internal {
87 
88 // This class wraps logic shared by all timers.
89 class BASE_EXPORT TimerBase {
90  public:
91   TimerBase(const TimerBase&) = delete;
92   TimerBase& operator=(const TimerBase&) = delete;
93 
94   virtual ~TimerBase();
95 
96   // Returns true if the timer is running (i.e., not stopped).
97   bool IsRunning() const;
98 
99   // Sets the task runner on which the delayed task should be scheduled when
100   // this Timer is running. This method can only be called while this Timer
101   // isn't running. If this is used to mock time in tests, the modern and
102   // preferred approach is to use TaskEnvironment::TimeSource::MOCK_TIME. To
103   // avoid racy usage of Timer, |task_runner| must run tasks on the same
104   // sequence which this Timer is bound to (started from). TODO(gab): Migrate
105   // callers using this as a test seam to
106   // TaskEnvironment::TimeSource::MOCK_TIME.
107   virtual void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner);
108 
109   // Call this method to stop the timer and cancel all previously scheduled
110   // tasks. It is a no-op if the timer is not running.
111   virtual void Stop();
112 
113  protected:
114   // Constructs a timer. Start must be called later to set task info.
115   explicit TimerBase(const Location& posted_from = Location());
116 
117   virtual void OnStop() = 0;
118 
119   // Disables the scheduled task and abandons it so that it no longer refers
120   // back to this object.
121   void AbandonScheduledTask();
122 
123   // Returns the task runner on which the task should be scheduled. If the
124   // corresponding |task_runner_| field is null, the task runner for the current
125   // sequence is returned.
126   scoped_refptr<SequencedTaskRunner> GetTaskRunner();
127 
128   // The task runner on which the task should be scheduled. If it is null, the
129   // task runner for the current sequence will be used.
130   scoped_refptr<SequencedTaskRunner> task_runner_;
131 
132   // Timer isn't thread-safe and while it is running, it must only be used on
133   // the same sequence until fully Stop()'ed. Once stopped, it may be destroyed
134   // or restarted on another sequence.
135   SEQUENCE_CHECKER(sequence_checker_);
136 
137   // Location in user code.
138   Location posted_from_ GUARDED_BY_CONTEXT(sequence_checker_);
139 
140   // The handle to the posted delayed task.
141   DelayedTaskHandle delayed_task_handle_ GUARDED_BY_CONTEXT(sequence_checker_);
142 
143   // Callback invoked when the timer is ready. This is saved as a member to
144   // avoid rebinding every time the Timer fires. Lazy initialized the first time
145   // the Timer is started.
146   RepeatingClosure timer_callback_;
147 };
148 
149 //-----------------------------------------------------------------------------
150 // This class wraps logic shared by (Retaining)OneShotTimer and RepeatingTimer.
151 class BASE_EXPORT DelayTimerBase : public TimerBase {
152  public:
153   DelayTimerBase(const DelayTimerBase&) = delete;
154   DelayTimerBase& operator=(const DelayTimerBase&) = delete;
155 
156   ~DelayTimerBase() override;
157 
158   // Returns the current delay for this timer.
159   TimeDelta GetCurrentDelay() const;
160 
161   // Call this method to reset the timer delay. The user task must be set. If
162   // the timer is not running, this will start it by posting a task.
163   virtual void Reset();
164 
165   // DEPRECATED. Call Stop() instead.
166   // TODO(1262205): Remove this method and all callers.
167   void AbandonAndStop();
168 
desired_run_time()169   TimeTicks desired_run_time() const {
170     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
171     return desired_run_time_;
172   }
173 
174  protected:
175   // Constructs a timer. Start must be called later to set task info.
176   // If |tick_clock| is provided, it is used instead of TimeTicks::Now() to get
177   // TimeTicks when scheduling tasks.
178   explicit DelayTimerBase(const TickClock* tick_clock = nullptr);
179 
180   // Construct a timer with task info.
181   // If |tick_clock| is provided, it is used instead of TimeTicks::Now() to get
182   // TimeTicks when scheduling tasks.
183   DelayTimerBase(const Location& posted_from,
184                  TimeDelta delay,
185                  const TickClock* tick_clock = nullptr);
186 
187   virtual void RunUserTask() = 0;
188 
189   // Schedules |OnScheduledTaskInvoked()| to run on the current sequence with
190   // the given |delay|. |desired_run_time_| is reset to Now() + delay.
191   void ScheduleNewTask(TimeDelta delay);
192 
193   void StartInternal(const Location& posted_from, TimeDelta delay);
194 
195  private:
196   // DCHECKs that the user task is not null. Used to diagnose a recurring bug
197   // where Reset() is called on a OneShotTimer that has already fired.
198   virtual void EnsureNonNullUserTask() = 0;
199 
200   // Returns the current tick count.
201   TimeTicks Now() const;
202 
203   // Called when the scheduled task is invoked. Will run the  |user_task| if the
204   // timer is still running and |desired_run_time_| was reached.
205   void OnScheduledTaskInvoked();
206 
207   // Delay requested by user.
208   TimeDelta delay_ GUARDED_BY_CONTEXT(sequence_checker_);
209 
210   // The desired run time of |user_task_|. The user may update this at any time,
211   // even if their previous request has not run yet. This time can be a "zero"
212   // TimeTicks if the task must be run immediately.
213   TimeTicks desired_run_time_ GUARDED_BY_CONTEXT(sequence_checker_);
214 
215   // The tick clock used to calculate the run time for scheduled tasks.
216   const raw_ptr<const TickClock> tick_clock_
217       GUARDED_BY_CONTEXT(sequence_checker_);
218 };
219 
220 }  // namespace internal
221 
222 //-----------------------------------------------------------------------------
223 // A simple, one-shot timer.  See usage notes at the top of the file.
224 class BASE_EXPORT OneShotTimer : public internal::DelayTimerBase {
225  public:
226   OneShotTimer();
227   explicit OneShotTimer(const TickClock* tick_clock);
228 
229   OneShotTimer(const OneShotTimer&) = delete;
230   OneShotTimer& operator=(const OneShotTimer&) = delete;
231 
232   ~OneShotTimer() override;
233 
234   // Start the timer to run at the given |delay| from now. If the timer is
235   // already running, it will be replaced to call the given |user_task|.
236   virtual void Start(const Location& posted_from,
237                      TimeDelta delay,
238                      OnceClosure user_task);
239 
240   // Start the timer to run at the given |delay| from now. If the timer is
241   // already running, it will be replaced to call a task formed from
242   // |receiver->*method|.
243   template <class Receiver>
Start(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)())244   void Start(const Location& posted_from,
245              TimeDelta delay,
246              Receiver* receiver,
247              void (Receiver::*method)()) {
248     Start(posted_from, delay, BindOnce(method, Unretained(receiver)));
249   }
250 
251   // Run the scheduled task immediately, and stop the timer. The timer needs to
252   // be running.
253   virtual void FireNow();
254 
255  private:
256   void OnStop() final;
257   void RunUserTask() final;
258   void EnsureNonNullUserTask() final;
259 
260   OnceClosure user_task_;
261 };
262 
263 //-----------------------------------------------------------------------------
264 // A simple, repeating timer.  See usage notes at the top of the file.
265 class BASE_EXPORT RepeatingTimer : public internal::DelayTimerBase {
266  public:
267   RepeatingTimer();
268   explicit RepeatingTimer(const TickClock* tick_clock);
269 
270   RepeatingTimer(const RepeatingTimer&) = delete;
271   RepeatingTimer& operator=(const RepeatingTimer&) = delete;
272 
273   ~RepeatingTimer() override;
274 
275   RepeatingTimer(const Location& posted_from,
276                  TimeDelta delay,
277                  RepeatingClosure user_task);
278   RepeatingTimer(const Location& posted_from,
279                  TimeDelta delay,
280                  RepeatingClosure user_task,
281                  const TickClock* tick_clock);
282 
283   // Start the timer to run at the given |delay| from now. If the timer is
284   // already running, it will be replaced to call the given |user_task|.
285   virtual void Start(const Location& posted_from,
286                      TimeDelta delay,
287                      RepeatingClosure user_task);
288 
289   // Start the timer to run at the given |delay| from now. If the timer is
290   // already running, it will be replaced to call a task formed from
291   // |receiver->*method|.
292   template <class Receiver>
Start(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)())293   void Start(const Location& posted_from,
294              TimeDelta delay,
295              Receiver* receiver,
296              void (Receiver::*method)()) {
297     Start(posted_from, delay, BindRepeating(method, Unretained(receiver)));
298   }
299 
user_task()300   const RepeatingClosure& user_task() const { return user_task_; }
301 
302  private:
303   // Mark this final, so that the destructor can call this safely.
304   void OnStop() final;
305   void RunUserTask() override;
306   void EnsureNonNullUserTask() final;
307 
308   RepeatingClosure user_task_;
309 };
310 
311 //-----------------------------------------------------------------------------
312 // A simple, one-shot timer with the retained |user_task| which is reused when
313 // Reset() is invoked. See usage notes at the top of the file.
314 class BASE_EXPORT RetainingOneShotTimer : public internal::DelayTimerBase {
315  public:
316   RetainingOneShotTimer();
317   explicit RetainingOneShotTimer(const TickClock* tick_clock);
318 
319   RetainingOneShotTimer(const RetainingOneShotTimer&) = delete;
320   RetainingOneShotTimer& operator=(const RetainingOneShotTimer&) = delete;
321 
322   ~RetainingOneShotTimer() override;
323 
324   RetainingOneShotTimer(const Location& posted_from,
325                         TimeDelta delay,
326                         RepeatingClosure user_task);
327   RetainingOneShotTimer(const Location& posted_from,
328                         TimeDelta delay,
329                         RepeatingClosure user_task,
330                         const TickClock* tick_clock);
331 
332   // Start the timer to run at the given |delay| from now. If the timer is
333   // already running, it will be replaced to call the given |user_task|.
334   virtual void Start(const Location& posted_from,
335                      TimeDelta delay,
336                      RepeatingClosure user_task);
337 
338   // Start the timer to run at the given |delay| from now. If the timer is
339   // already running, it will be replaced to call a task formed from
340   // |receiver->*method|.
341   template <class Receiver>
Start(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)())342   void Start(const Location& posted_from,
343              TimeDelta delay,
344              Receiver* receiver,
345              void (Receiver::*method)()) {
346     Start(posted_from, delay, BindRepeating(method, Unretained(receiver)));
347   }
348 
user_task()349   const RepeatingClosure& user_task() const { return user_task_; }
350 
351  private:
352   // Mark this final, so that the destructor can call this safely.
353   void OnStop() final;
354   void RunUserTask() override;
355   void EnsureNonNullUserTask() final;
356 
357   RepeatingClosure user_task_;
358 };
359 
360 //-----------------------------------------------------------------------------
361 // A Delay timer is like The Button from Lost. Once started, you have to keep
362 // calling Reset otherwise it will call the given method on the sequence it was
363 // initially Reset() from.
364 //
365 // Once created, it is inactive until Reset is called. Once |delay| seconds have
366 // passed since the last call to Reset, the callback is made. Once the callback
367 // has been made, it's inactive until Reset is called again.
368 //
369 // If destroyed, the timeout is canceled and will not occur even if already
370 // inflight.
371 class DelayTimer {
372  public:
373   template <class Receiver>
DelayTimer(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)())374   DelayTimer(const Location& posted_from,
375              TimeDelta delay,
376              Receiver* receiver,
377              void (Receiver::*method)())
378       : DelayTimer(posted_from, delay, receiver, method, nullptr) {}
379 
380   template <class Receiver>
DelayTimer(const Location & posted_from,TimeDelta delay,Receiver * receiver,void (Receiver::* method)(),const TickClock * tick_clock)381   DelayTimer(const Location& posted_from,
382              TimeDelta delay,
383              Receiver* receiver,
384              void (Receiver::*method)(),
385              const TickClock* tick_clock)
386       : timer_(posted_from,
387                delay,
388                BindRepeating(method, Unretained(receiver)),
389                tick_clock) {}
390 
391   DelayTimer(const DelayTimer&) = delete;
392   DelayTimer& operator=(const DelayTimer&) = delete;
393 
Reset()394   void Reset() { timer_.Reset(); }
395 
396  private:
397   RetainingOneShotTimer timer_;
398 };
399 
400 //-----------------------------------------------------------------------------
401 // A one-shot timer that attempts to run |user_task| some time near specified
402 // deadline. See usage notes at the top of the file.
403 class BASE_EXPORT DeadlineTimer : public internal::TimerBase {
404  public:
405   DeadlineTimer();
406   ~DeadlineTimer() override;
407 
408   DeadlineTimer(const DeadlineTimer&) = delete;
409   DeadlineTimer& operator=(const DeadlineTimer&) = delete;
410 
411   // Start the timer to run |user_task| near the specified |deadline| following
412   // |delay_policy| If the timer is already running, it will be replaced to call
413   // the given |user_task|.
414   void Start(const Location& posted_from,
415              TimeTicks deadline,
416              OnceClosure user_task,
417              subtle::DelayPolicy delay_policy =
418                  subtle::DelayPolicy::kFlexiblePreferEarly);
419 
420   // Start the timer to run |user_task| near the specified |deadline|. If the
421   // timer is already running, it will be replaced to call a task formed from
422   // |receiver->*method|.
423   template <class Receiver>
424   void Start(const Location& posted_from,
425              TimeTicks deadline,
426              Receiver* receiver,
427              void (Receiver::*method)(),
428              subtle::DelayPolicy delay_policy =
429                  subtle::DelayPolicy::kFlexiblePreferEarly) {
430     Start(posted_from, deadline, BindOnce(method, Unretained(receiver)),
431           delay_policy);
432   }
433 
434  protected:
435   void OnStop() override;
436 
437   // Schedules |OnScheduledTaskInvoked()| to run on the current sequence at
438   // the given |deadline|.
439   void ScheduleNewTask(TimeTicks deadline, subtle::DelayPolicy delay_policy);
440 
441  private:
442   // Called when the scheduled task is invoked to run the |user_task|.
443   void OnScheduledTaskInvoked();
444 
445   OnceClosure user_task_;
446 };
447 
448 //-----------------------------------------------------------------------------
449 // Repeatedly invokes a callback, waiting for a precise delay between the
450 // beginning of each invocation. See usage notes at the top of the file.
451 class BASE_EXPORT MetronomeTimer : public internal::TimerBase {
452  public:
453   MetronomeTimer();
454   ~MetronomeTimer() override;
455 
456   MetronomeTimer(const MetronomeTimer&) = delete;
457   MetronomeTimer& operator=(const MetronomeTimer&) = delete;
458 
459   MetronomeTimer(const Location& posted_from,
460                  TimeDelta interval,
461                  RepeatingClosure user_task,
462                  TimeTicks phase = TimeTicks());
463 
464   // Start the timer to repeatedly run |user_task| at the specified |interval|;
465   // If not specified, the phase is up to the scheduler, otherwise each
466   // invocation starts as close as possible to `phase + n * delay` for some
467   // integer n. If the timer is already running, it will be replaced to call the
468   // given |user_task|.
469   void Start(const Location& posted_from,
470              TimeDelta interval,
471              RepeatingClosure user_task,
472              TimeTicks phase = TimeTicks());
473 
474   // Same as the previous overload, except that the user task is specified by
475   // `receiver` and `method`.
476   template <class Receiver>
477   void Start(const Location& posted_from,
478              TimeDelta interval,
479              Receiver* receiver,
480              void (Receiver::*method)(),
481              TimeTicks phase = TimeTicks()) {
482     Start(posted_from, interval, BindRepeating(method, Unretained(receiver)),
483           phase);
484   }
485 
486   // Call this method to reset the timer delay. The user task must be set. If
487   // the timer is not running, this will start it by posting a task.
488   void Reset();
489 
490  protected:
491   void OnStop() override;
492 
493   // Schedules |OnScheduledTaskInvoked()| to run on the current sequence at
494   // the next tick.
495   void ScheduleNewTask();
496 
497  private:
498   // Called when the scheduled task is invoked to run the |user_task|.
499   void OnScheduledTaskInvoked();
500 
501   TimeDelta interval_;
502   RepeatingClosure user_task_;
503   TimeTicks phase_;
504 };
505 
506 }  // namespace base
507 
508 #endif  // BASE_TIMER_TIMER_H_
509