blob: cb20bde19e5aaa5b19913b6b3bb046a8addbdd41 [file] [log] [blame]
[email protected]89bf27e2013-06-27 18:04:561// 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
tzikd93bb0862018-07-19 11:54:145// OneShotTimer, RepeatingTimer and RetainingOneShotTimer provide a simple timer
6// API. As the names suggest, OneShotTimer calls you back once after a time
7// delay expires.
[email protected]89bf27e2013-06-27 18:04:568// RepeatingTimer on the other hand calls you back periodically with the
9// prescribed time interval.
Owen Min9bbee7d32019-04-29 15:31:4010// RetainingOneShotTimer doesn't repeat the task itself like RepeatingTimer, but
tzikd93bb0862018-07-19 11:54:1411// retains the given task after the time out. You can restart it with Reset
12// again without giving new task to Start.
[email protected]89bf27e2013-06-27 18:04:5613//
tzikd93bb0862018-07-19 11:54:1414// All of OneShotTimer, RepeatingTimer and RetainingOneShotTimer cancel the
15// timer when they go out of scope, which makes it easy to ensure that you do
16// not get called when your object has gone out of scope. Just instantiate a
17// timer as a member variable of the class for which you wish to receive timer
18// events.
[email protected]89bf27e2013-06-27 18:04:5619//
20// Sample RepeatingTimer usage:
21//
22// class MyClass {
23// public:
24// void StartDoingStuff() {
Peter Kasting53fd6ee2021-10-05 20:40:4825// timer_.Start(FROM_HERE, Seconds(1),
[email protected]89bf27e2013-06-27 18:04:5626// this, &MyClass::DoStuff);
27// }
28// void StopDoingStuff() {
29// timer_.Stop();
30// }
31// private:
32// void DoStuff() {
33// // This method is called every second to do stuff.
34// ...
35// }
danakj8c3eb802015-09-24 07:53:0036// base::RepeatingTimer timer_;
[email protected]89bf27e2013-06-27 18:04:5637// };
38//
tzikd93bb0862018-07-19 11:54:1439// Timers also support a Reset method, which allows you to easily defer the
40// timer event until the timer delay passes once again. So, in the above
41// example, if 0.5 seconds have already passed, calling Reset on |timer_|
42// would postpone DoStuff by another 1 second. In other words, Reset is
43// shorthand for calling Stop and then Start again with the same arguments.
[email protected]89bf27e2013-06-27 18:04:5644//
Gabriel Charettee92ccc02019-01-19 14:13:0545// These APIs are not thread safe. When a method is called (except the
46// constructor), all further method calls must be on the same sequence until
Patrick Monettec4d306d2021-06-23 19:15:2547// Stop(). Once stopped, it may be destroyed or restarted on another sequence.
ossu87340af2017-07-06 09:02:1548//
49// By default, the scheduled tasks will be run on the same sequence that the
Gabriel Charettee92ccc02019-01-19 14:13:0550// Timer was *started on*. To mock time in unit tests, some old tests used
51// SetTaskRunner() to schedule the delay on a test-controlled TaskRunner. The
Gabriel Charette694c3c332019-08-19 14:53:0552// modern and preferred approach to mock time is to use TaskEnvironment's
Gabriel Charettee92ccc02019-01-19 14:13:0553// MOCK_TIME mode.
[email protected]89bf27e2013-06-27 18:04:5654
55#ifndef BASE_TIMER_TIMER_H_
56#define BASE_TIMER_TIMER_H_
57
58// IMPORTANT: If you change timer code, make sure that all tests (including
59// disabled ones) from timer_unittests.cc pass locally. Some are disabled
60// because they're flaky on the buildbot, but when you run them locally you
61// should be able to tell the difference.
62
63#include "base/base_export.h"
64#include "base/bind.h"
[email protected]89bf27e2013-06-27 18:04:5665#include "base/callback.h"
danakjdb9ae7942020-11-11 16:01:3566#include "base/callback_helpers.h"
[email protected]89bf27e2013-06-27 18:04:5667#include "base/location.h"
avi9b6f42932015-12-26 22:15:1468#include "base/macros.h"
Patrick Monettec4d306d2021-06-23 19:15:2569#include "base/sequence_checker.h"
Patrick Monette643cdf62021-10-15 19:13:4270#include "base/task/sequenced_task_runner.h"
[email protected]89bf27e2013-06-27 18:04:5671#include "base/time/time.h"
72
73namespace base {
74
jameswest6e0c8d22016-11-15 05:19:5475class TickClock;
[email protected]89bf27e2013-06-27 18:04:5676
tzikd93bb0862018-07-19 11:54:1477namespace internal {
78
Patrick Monette57d1c18d2021-04-22 00:50:4479class TaskDestructionDetector;
tzikd93bb0862018-07-19 11:54:1480
[email protected]89bf27e2013-06-27 18:04:5681//-----------------------------------------------------------------------------
gab4e844bb2017-06-01 16:23:3682// This class wraps TaskRunner::PostDelayedTask to manage delayed and repeating
83// tasks. See meta comment above for thread-safety requirements.
tzikd93bb0862018-07-19 11:54:1484// Do not use this class directly. Use one of OneShotTimer, RepeatingTimer or
85// RetainingOneShotTimer.
[email protected]89bf27e2013-06-27 18:04:5686//
tzikd93bb0862018-07-19 11:54:1487class BASE_EXPORT TimerBase {
[email protected]89bf27e2013-06-27 18:04:5688 public:
tzikf3336c92018-07-25 03:15:5089 // Constructs a timer. Start must be called later to set task info.
90 // If |tick_clock| is provided, it is used instead of TimeTicks::Now() to get
91 // TimeTicks when scheduling tasks.
92 TimerBase();
93 explicit TimerBase(const TickClock* tick_clock);
[email protected]89bf27e2013-06-27 18:04:5694
tzikf3336c92018-07-25 03:15:5095 // Construct a timer with task info.
96 // If |tick_clock| is provided, it is used instead of TimeTicks::Now() to get
97 // TimeTicks when scheduling tasks.
98 TimerBase(const Location& posted_from, TimeDelta delay);
tzikd93bb0862018-07-19 11:54:1499 TimerBase(const Location& posted_from,
100 TimeDelta delay,
tzikd93bb0862018-07-19 11:54:14101 const TickClock* tick_clock);
[email protected]89bf27e2013-06-27 18:04:56102
Peter Boström7319bbd2021-09-15 22:59:38103 TimerBase(const TimerBase&) = delete;
104 TimerBase& operator=(const TimerBase&) = delete;
105
tzikd93bb0862018-07-19 11:54:14106 virtual ~TimerBase();
[email protected]89bf27e2013-06-27 18:04:56107
108 // Returns true if the timer is running (i.e., not stopped).
tzik84db8912018-06-19 06:08:54109 bool IsRunning() const;
[email protected]89bf27e2013-06-27 18:04:56110
111 // Returns the current delay for this timer.
tzik84db8912018-06-19 06:08:54112 TimeDelta GetCurrentDelay() const;
[email protected]89bf27e2013-06-27 18:04:56113
Gabriel Charettee92ccc02019-01-19 14:13:05114 // Sets the task runner on which the delayed task should be scheduled when
115 // this Timer is running. This method can only be called while this Timer
116 // isn't running. This is an alternative (old) approach to mock time in tests.
117 // The modern and preferred approach is to use
Gabriel Charette694c3c332019-08-19 14:53:05118 // TaskEnvironment::TimeSource::MOCK_TIME. To avoid racy usage of Timer,
Gabriel Charettee92ccc02019-01-19 14:13:05119 // |task_runner| must run tasks on the same sequence which this Timer is bound
Gabriel Charettec9a37f02019-07-15 22:32:02120 // to (started from). TODO(gab): Migrate all callers to
Gabriel Charette694c3c332019-08-19 14:53:05121 // TaskEnvironment::TimeSource::MOCK_TIME.
tzik84db8912018-06-19 06:08:54122 virtual void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner);
petrcermak7652da6d2014-11-06 02:17:57123
Patrick Monette57d1c18d2021-04-22 00:50:44124 // Call this method to stop and cancel the timer. It is a no-op if the timer
[email protected]89bf27e2013-06-27 18:04:56125 // is not running.
[email protected]9df013b2014-03-13 22:04:39126 virtual void Stop();
[email protected]89bf27e2013-06-27 18:04:56127
Patrick Monette57d1c18d2021-04-22 00:50:44128 // Abandons the scheduled task (if any) and stops the timer (if running).
ossu87340af2017-07-06 09:02:15129 void AbandonAndStop() {
130 AbandonScheduledTask();
131
132 Stop();
133 // No more member accesses here: |this| could be deleted at this point.
134 }
135
tzikf3336c92018-07-25 03:15:50136 // Call this method to reset the timer delay. The user task must be set. If
[email protected]89bf27e2013-06-27 18:04:56137 // the timer is not running, this will start it by posting a task.
[email protected]9df013b2014-03-13 22:04:39138 virtual void Reset();
[email protected]89bf27e2013-06-27 18:04:56139
[email protected]89bf27e2013-06-27 18:04:56140 const TimeTicks& desired_run_time() const { return desired_run_time_; }
141
142 protected:
tzikf3336c92018-07-25 03:15:50143 virtual void OnStop() = 0;
144 virtual void RunUserTask() = 0;
145
tzikf550a612018-07-12 02:25:34146 // The task runner on which the task should be scheduled. If it is null, the
147 // task runner for the current sequence will be used.
148 scoped_refptr<SequencedTaskRunner> task_runner_;
149
Patrick Monettec4d306d2021-06-23 19:15:25150 // Timer isn't thread-safe and while it is running, it must only be used on
151 // the same sequence until fully Stop()'ed. Once stopped, it may be destroyed
152 // or restarted on another sequence.
153 SEQUENCE_CHECKER(sequence_checker_);
tzikf550a612018-07-12 02:25:34154
Patrick Monette57d1c18d2021-04-22 00:50:44155 // Schedules |OnScheduledTaskInvoked()| to run on the current sequence with
156 // the given |delay|. |scheduled_run_time_| and |desired_run_time_| are reset
157 // to Now() + delay.
158 void ScheduleNewTask(TimeDelta delay);
[email protected]89bf27e2013-06-27 18:04:56159
tzikf3336c92018-07-25 03:15:50160 void StartInternal(const Location& posted_from, TimeDelta delay);
161
162 private:
163 friend class BaseTimerTaskInternal;
164
jsbell763cd402015-12-17 00:38:27165 // Returns the task runner on which the task should be scheduled. If the
gab4e844bb2017-06-01 16:23:36166 // corresponding |task_runner_| field is null, the task runner for the current
167 // sequence is returned.
168 scoped_refptr<SequencedTaskRunner> GetTaskRunner();
petrcermak7652da6d2014-11-06 02:17:57169
Patrick Monette400b05142021-04-21 22:28:35170 // Returns the current tick count.
171 TimeTicks Now() const;
172
Patrick Monette57d1c18d2021-04-22 00:50:44173 // Disables the scheduled task and abandon it so that it no longer refers back
gab4e844bb2017-06-01 16:23:36174 // to this object.
[email protected]89bf27e2013-06-27 18:04:56175 void AbandonScheduledTask();
176
Patrick Monette57d1c18d2021-04-22 00:50:44177 // Called when the scheduled task is invoked. Will run the |user_task| if the
178 // timer is still running and |desired_run_time_| was reached.
179 // |task_destruction_detector| is owned by the callback to detect when the
180 // scheduled task is deleted before being executed.
181 void OnScheduledTaskInvoked(
182 std::unique_ptr<TaskDestructionDetector> task_destruction_detector);
[email protected]89bf27e2013-06-27 18:04:56183
Patrick Monette57d1c18d2021-04-22 00:50:44184 // Detects when the scheduled task is deleted before being executed. Null when
185 // there is no scheduled task.
Patrick Monettec4d306d2021-06-23 19:15:25186 TaskDestructionDetector* task_destruction_detector_
187 GUARDED_BY_CONTEXT(sequence_checker_);
[email protected]89bf27e2013-06-27 18:04:56188
189 // Location in user code.
Patrick Monettec4d306d2021-06-23 19:15:25190 Location posted_from_ GUARDED_BY_CONTEXT(sequence_checker_);
[email protected]89bf27e2013-06-27 18:04:56191 // Delay requested by user.
Patrick Monettec4d306d2021-06-23 19:15:25192 TimeDelta delay_ GUARDED_BY_CONTEXT(sequence_checker_);
[email protected]89bf27e2013-06-27 18:04:56193
Patrick Monette57d1c18d2021-04-22 00:50:44194 // The time at which the scheduled task is expected to fire. This time can be
195 // null if the task must be run immediately.
Patrick Monettec4d306d2021-06-23 19:15:25196 TimeTicks scheduled_run_time_ GUARDED_BY_CONTEXT(sequence_checker_);
[email protected]89bf27e2013-06-27 18:04:56197
gab4e844bb2017-06-01 16:23:36198 // The desired run time of |user_task_|. The user may update this at any time,
199 // even if their previous request has not run yet. If |desired_run_time_| is
200 // greater than |scheduled_run_time_|, a continuation task will be posted to
[email protected]89bf27e2013-06-27 18:04:56201 // wait for the remaining time. This allows us to reuse the pending task so as
gab4e844bb2017-06-01 16:23:36202 // not to flood the delayed queues with orphaned tasks when the user code
[email protected]d04519352013-12-04 20:05:45203 // excessively Stops and Starts the timer. This time can be a "zero" TimeTicks
204 // if the task must be run immediately.
Patrick Monettec4d306d2021-06-23 19:15:25205 TimeTicks desired_run_time_ GUARDED_BY_CONTEXT(sequence_checker_);
[email protected]89bf27e2013-06-27 18:04:56206
jameswest6e0c8d22016-11-15 05:19:54207 // The tick clock used to calculate the run time for scheduled tasks.
Patrick Monettec4d306d2021-06-23 19:15:25208 const TickClock* const tick_clock_ GUARDED_BY_CONTEXT(sequence_checker_);
jameswest6e0c8d22016-11-15 05:19:54209
gab4e844bb2017-06-01 16:23:36210 // If true, |user_task_| is scheduled to run sometime in the future.
Patrick Monettec4d306d2021-06-23 19:15:25211 bool is_running_ GUARDED_BY_CONTEXT(sequence_checker_);
[email protected]89bf27e2013-06-27 18:04:56212
Patrick Monettec4d306d2021-06-23 19:15:25213 WeakPtrFactory<TimerBase> weak_ptr_factory_
214 GUARDED_BY_CONTEXT(sequence_checker_){this};
[email protected]89bf27e2013-06-27 18:04:56215};
216
tzikd93bb0862018-07-19 11:54:14217} // namespace internal
218
[email protected]89bf27e2013-06-27 18:04:56219//-----------------------------------------------------------------------------
[email protected]89bf27e2013-06-27 18:04:56220// A simple, one-shot timer. See usage notes at the top of the file.
tzikd93bb0862018-07-19 11:54:14221class BASE_EXPORT OneShotTimer : public internal::TimerBase {
danakj8c3eb802015-09-24 07:53:00222 public:
tzikf3336c92018-07-25 03:15:50223 OneShotTimer();
224 explicit OneShotTimer(const TickClock* tick_clock);
Peter Boström7319bbd2021-09-15 22:59:38225
226 OneShotTimer(const OneShotTimer&) = delete;
227 OneShotTimer& operator=(const OneShotTimer&) = delete;
228
tzikf3336c92018-07-25 03:15:50229 ~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
Ming-Chuan Lin1b43b402020-02-27 17:53:39239 // |receiver->*method|.
tzikf3336c92018-07-25 03:15:50240 template <class Receiver>
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 }
tzikf550a612018-07-12 02:25:34247
248 // Run the scheduled task immediately, and stop the timer. The timer needs to
249 // be running.
250 void FireNow();
tzikf3336c92018-07-25 03:15:50251
252 private:
253 void OnStop() final;
254 void RunUserTask() final;
255
256 OnceClosure user_task_;
danakj8c3eb802015-09-24 07:53:00257};
[email protected]89bf27e2013-06-27 18:04:56258
259//-----------------------------------------------------------------------------
260// A simple, repeating timer. See usage notes at the top of the file.
tzikf3336c92018-07-25 03:15:50261class BASE_EXPORT RepeatingTimer : public internal::TimerBase {
danakj8c3eb802015-09-24 07:53:00262 public:
tzikf3336c92018-07-25 03:15:50263 RepeatingTimer();
264 explicit RepeatingTimer(const TickClock* tick_clock);
Peter Boström7319bbd2021-09-15 22:59:38265
266 RepeatingTimer(const RepeatingTimer&) = delete;
267 RepeatingTimer& operator=(const RepeatingTimer&) = delete;
268
tzikf3336c92018-07-25 03:15:50269 ~RepeatingTimer() override;
tzik524daae92018-07-05 02:52:02270
271 RepeatingTimer(const Location& posted_from,
272 TimeDelta delay,
tzikf3336c92018-07-25 03:15:50273 RepeatingClosure user_task);
tzik524daae92018-07-05 02:52:02274 RepeatingTimer(const Location& posted_from,
275 TimeDelta delay,
276 RepeatingClosure user_task,
tzikf3336c92018-07-25 03:15:50277 const TickClock* tick_clock);
278
279 // Start the timer to run at the given |delay| from now. If the timer is
280 // already running, it will be replaced to call the given |user_task|.
281 virtual void Start(const Location& posted_from,
282 TimeDelta delay,
283 RepeatingClosure user_task);
284
285 // Start the timer to run at the given |delay| from now. If the timer is
286 // already running, it will be replaced to call a task formed from
Ming-Chuan Lin1b43b402020-02-27 17:53:39287 // |receiver->*method|.
tzikf3336c92018-07-25 03:15:50288 template <class Receiver>
289 void Start(const Location& posted_from,
290 TimeDelta delay,
291 Receiver* receiver,
292 void (Receiver::*method)()) {
293 Start(posted_from, delay, BindRepeating(method, Unretained(receiver)));
294 }
295
296 const RepeatingClosure& user_task() const { return user_task_; }
297
298 private:
299 // Mark this final, so that the destructor can call this safely.
300 void OnStop() final;
301
302 void RunUserTask() override;
303
304 RepeatingClosure user_task_;
danakj8c3eb802015-09-24 07:53:00305};
[email protected]89bf27e2013-06-27 18:04:56306
307//-----------------------------------------------------------------------------
danakj8c1f3bf2019-12-11 22:21:02308// A simple, one-shot timer with the retained user_task which is reused for
309// multiple invocations of Start(). See usage notes at the top of the file.
tzikf3336c92018-07-25 03:15:50310class BASE_EXPORT RetainingOneShotTimer : public internal::TimerBase {
tzik57c66e32018-07-02 08:02:57311 public:
tzikf3336c92018-07-25 03:15:50312 RetainingOneShotTimer();
313 explicit RetainingOneShotTimer(const TickClock* tick_clock);
Peter Boström7319bbd2021-09-15 22:59:38314
315 RetainingOneShotTimer(const RetainingOneShotTimer&) = delete;
316 RetainingOneShotTimer& operator=(const RetainingOneShotTimer&) = delete;
317
tzikf3336c92018-07-25 03:15:50318 ~RetainingOneShotTimer() override;
tzik524daae92018-07-05 02:52:02319
320 RetainingOneShotTimer(const Location& posted_from,
321 TimeDelta delay,
tzikf3336c92018-07-25 03:15:50322 RepeatingClosure user_task);
tzik524daae92018-07-05 02:52:02323 RetainingOneShotTimer(const Location& posted_from,
324 TimeDelta delay,
325 RepeatingClosure user_task,
tzikf3336c92018-07-25 03:15:50326 const TickClock* tick_clock);
327
328 // Start the timer to run at the given |delay| from now. If the timer is
329 // already running, it will be replaced to call the given |user_task|.
330 virtual void Start(const Location& posted_from,
331 TimeDelta delay,
332 RepeatingClosure user_task);
333
334 // Start the timer to run at the given |delay| from now. If the timer is
335 // already running, it will be replaced to call a task formed from
Ming-Chuan Lin1b43b402020-02-27 17:53:39336 // |receiver->*method|.
tzikf3336c92018-07-25 03:15:50337 template <class Receiver>
338 void Start(const Location& posted_from,
339 TimeDelta delay,
340 Receiver* receiver,
341 void (Receiver::*method)()) {
342 Start(posted_from, delay, BindRepeating(method, Unretained(receiver)));
343 }
344
345 const RepeatingClosure& user_task() const { return user_task_; }
346
tzikf3336c92018-07-25 03:15:50347 private:
348 // Mark this final, so that the destructor can call this safely.
349 void OnStop() final;
350
351 void RunUserTask() override;
352
353 RepeatingClosure user_task_;
tzik57c66e32018-07-02 08:02:57354};
355
356//-----------------------------------------------------------------------------
[email protected]89bf27e2013-06-27 18:04:56357// A Delay timer is like The Button from Lost. Once started, you have to keep
gab4e844bb2017-06-01 16:23:36358// calling Reset otherwise it will call the given method on the sequence it was
359// initially Reset() from.
[email protected]89bf27e2013-06-27 18:04:56360//
361// Once created, it is inactive until Reset is called. Once |delay| seconds have
362// passed since the last call to Reset, the callback is made. Once the callback
363// has been made, it's inactive until Reset is called again.
364//
365// If destroyed, the timeout is canceled and will not occur even if already
366// inflight.
tzik32c3bcd2018-07-09 04:39:38367class DelayTimer {
[email protected]89bf27e2013-06-27 18:04:56368 public:
danakj8c3eb802015-09-24 07:53:00369 template <class Receiver>
Brett Wilson8e88b312017-09-12 05:22:16370 DelayTimer(const Location& posted_from,
[email protected]89bf27e2013-06-27 18:04:56371 TimeDelta delay,
372 Receiver* receiver,
danakj8c3eb802015-09-24 07:53:00373 void (Receiver::*method)())
jameswest6e0c8d22016-11-15 05:19:54374 : DelayTimer(posted_from, delay, receiver, method, nullptr) {}
375
376 template <class Receiver>
Brett Wilson8e88b312017-09-12 05:22:16377 DelayTimer(const Location& posted_from,
jameswest6e0c8d22016-11-15 05:19:54378 TimeDelta delay,
379 Receiver* receiver,
380 void (Receiver::*method)(),
Greg Thompsonaa48ce8d2018-04-03 06:11:43381 const TickClock* tick_clock)
tzik32c3bcd2018-07-09 04:39:38382 : timer_(posted_from,
383 delay,
384 BindRepeating(method, Unretained(receiver)),
385 tick_clock) {}
[email protected]89bf27e2013-06-27 18:04:56386
Peter Boström75cd3c02021-09-28 15:23:18387 DelayTimer(const DelayTimer&) = delete;
388 DelayTimer& operator=(const DelayTimer&) = delete;
389
tzik32c3bcd2018-07-09 04:39:38390 void Reset() { timer_.Reset(); }
391
392 private:
393 RetainingOneShotTimer timer_;
[email protected]89bf27e2013-06-27 18:04:56394};
395
[email protected]89bf27e2013-06-27 18:04:56396} // namespace base
397
398#endif // BASE_TIMER_TIMER_H_