blob: 9a0a45155f9b6db73c9cd1438c2d7dfdb8375edf [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
[email protected]8f9a3a52013-06-28 15:14:185#include "base/timer/timer.h"
[email protected]a5b94a92008-08-12 23:25:436
[email protected]c014f2b32013-09-03 23:29:127#include <stddef.h>
8
jameswest6e0c8d22016-11-15 05:19:549#include <utility>
10
Hans Wennborgc3cffa62020-04-27 10:09:1211#include "base/check.h"
Patrick Monettebdc1bae52021-09-14 16:15:1412#include "base/feature_list.h"
jameswest6e0c8d22016-11-15 05:19:5413#include "base/memory/ptr_util.h"
Keishi Hattori488b7602022-05-02 13:09:3114#include "base/memory/raw_ptr_exclusion.h"
[email protected]c014f2b32013-09-03 23:29:1215#include "base/memory/ref_counted.h"
Sean Maher7d0e8052022-12-09 01:46:3216#include "base/task/sequenced_task_runner.h"
Patrick Monette4efba9c2022-08-18 16:41:3217#include "base/task/task_features.h"
jsbell763cd402015-12-17 00:38:2718#include "base/threading/platform_thread.h"
jameswest6e0c8d22016-11-15 05:19:5419#include "base/time/tick_clock.h"
initial.commitd7cae122008-07-26 21:49:3820
[email protected]aeab57ea2008-08-28 20:50:1221namespace base {
tzikd93bb0862018-07-19 11:54:1422namespace internal {
[email protected]aeab57ea2008-08-28 20:50:1223
Etienne Pierre-doray9c3d17d82022-05-12 22:05:2924TimerBase::TimerBase(const Location& posted_from) : posted_from_(posted_from) {
gab4e844bb2017-06-01 16:23:3625 // It is safe for the timer to be created on a different thread/sequence than
26 // the one from which the timer APIs are called. The first call to the
27 // checker's CalledOnValidSequence() method will re-bind the checker, and
28 // later calls will verify that the same task runner is used.
Patrick Monettec4d306d2021-06-23 19:15:2529 DETACH_FROM_SEQUENCE(sequence_checker_);
gab4e844bb2017-06-01 16:23:3630}
[email protected]df9076a2012-03-27 00:18:5731
tzikd93bb0862018-07-19 11:54:1432TimerBase::~TimerBase() {
Patrick Monettec4d306d2021-06-23 19:15:2533 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tzikf3336c92018-07-25 03:15:5034 AbandonScheduledTask();
[email protected]df9076a2012-03-27 00:18:5735}
36
tzikd93bb0862018-07-19 11:54:1437bool TimerBase::IsRunning() const {
Patrick Monettec4d306d2021-06-23 19:15:2538 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Etienne Pierre-doray9c3d17d82022-05-12 22:05:2939 return delayed_task_handle_.IsValid();
[email protected]9df013b2014-03-13 22:04:3940}
41
tzikd93bb0862018-07-19 11:54:1442void TimerBase::SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) {
Patrick Monettec4d306d2021-06-23 19:15:2543 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Gabriel Charettee92ccc02019-01-19 14:13:0544 DCHECK(task_runner->RunsTasksInCurrentSequence());
45 DCHECK(!IsRunning());
jsbell763cd402015-12-17 00:38:2746 task_runner_.swap(task_runner);
petrcermak7652da6d2014-11-06 02:17:5747}
48
Etienne Pierre-doray1a0edc72022-01-14 15:11:4449scoped_refptr<SequencedTaskRunner> TimerBase::GetTaskRunner() {
Sean Maher7d0e8052022-12-09 01:46:3250 return task_runner_ ? task_runner_ : SequencedTaskRunner::GetCurrentDefault();
[email protected]df9076a2012-03-27 00:18:5751}
52
tzikd93bb0862018-07-19 11:54:1453void TimerBase::Stop() {
Patrick Monettec4d306d2021-06-23 19:15:2554 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab4e844bb2017-06-01 16:23:3655
Etienne Pierre-doray1a0edc72022-01-14 15:11:4456 AbandonScheduledTask();
Patrick Monettebdc1bae52021-09-14 16:15:1457
tzikf3336c92018-07-25 03:15:5058 OnStop();
59 // No more member accesses here: |this| could be deleted after Stop() call.
[email protected]df9076a2012-03-27 00:18:5760}
61
Etienne Pierre-doray1a0edc72022-01-14 15:11:4462void TimerBase::AbandonScheduledTask() {
63 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
64
Peter Kasting134ef9af2024-12-28 02:30:0965 if (delayed_task_handle_.IsValid()) {
Etienne Pierre-doray1a0edc72022-01-14 15:11:4466 delayed_task_handle_.CancelTask();
Peter Kasting134ef9af2024-12-28 02:30:0967 }
Etienne Pierre-doray1a0edc72022-01-14 15:11:4468
69 // It's safe to destroy or restart Timer on another sequence after the task is
70 // abandoned.
71 DETACH_FROM_SEQUENCE(sequence_checker_);
72}
73
74DelayTimerBase::DelayTimerBase(const TickClock* tick_clock)
75 : tick_clock_(tick_clock) {}
76
77DelayTimerBase::DelayTimerBase(const Location& posted_from,
78 TimeDelta delay,
79 const TickClock* tick_clock)
80 : TimerBase(posted_from), delay_(delay), tick_clock_(tick_clock) {}
81
82DelayTimerBase::~DelayTimerBase() = default;
83
84TimeDelta DelayTimerBase::GetCurrentDelay() const {
85 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
86 return delay_;
87}
88
89void DelayTimerBase::StartInternal(const Location& posted_from,
90 TimeDelta delay) {
91 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
92
93 posted_from_ = posted_from;
94 delay_ = delay;
95
96 Reset();
97}
98
Etienne Pierre-doray1a0edc72022-01-14 15:11:4499void DelayTimerBase::Reset() {
Patrick Monettec4d306d2021-06-23 19:15:25100 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]df9076a2012-03-27 00:18:57101
Patrick Monette478af572022-01-20 20:34:15102 EnsureNonNullUserTask();
103
gab4e844bb2017-06-01 16:23:36104 // We can't reuse the |scheduled_task_|, so abandon it and post a new one.
[email protected]df9076a2012-03-27 00:18:57105 AbandonScheduledTask();
Patrick Monette57d1c18d2021-04-22 00:50:44106 ScheduleNewTask(delay_);
[email protected]df9076a2012-03-27 00:18:57107}
108
Etienne Pierre-doray1a0edc72022-01-14 15:11:44109void DelayTimerBase::ScheduleNewTask(TimeDelta delay) {
Patrick Monettec4d306d2021-06-23 19:15:25110 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Etienne Pierre-doray9c3d17d82022-05-12 22:05:29111 DCHECK(!delayed_task_handle_.IsValid());
Patrick Monette6994b91f2021-11-01 19:19:04112
113 // Ignore negative deltas.
114 // TODO(pmonette): Fix callers providing negative deltas and ban passing them.
Peter Kasting134ef9af2024-12-28 02:30:09115 if (delay < TimeDelta()) {
Patrick Monette6994b91f2021-11-01 19:19:04116 delay = TimeDelta();
Peter Kasting134ef9af2024-12-28 02:30:09117 }
Patrick Monette6994b91f2021-11-01 19:19:04118
Etienne Pierre-dorayf16856862022-06-10 18:49:02119 if (!timer_callback_) {
120 timer_callback_ = BindRepeating(&DelayTimerBase::OnScheduledTaskInvoked,
121 Unretained(this));
122 }
Patrick Monette6994b91f2021-11-01 19:19:04123 delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTask(
Etienne Pierre-dorayf16856862022-06-10 18:49:02124 base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_,
Patrick Monette6994b91f2021-11-01 19:19:04125 delay);
Etienne Pierre-doray8c6860d2023-03-22 20:18:49126 desired_run_time_ = Now() + delay;
[email protected]df9076a2012-03-27 00:18:57127}
128
Etienne Pierre-doray1a0edc72022-01-14 15:11:44129TimeTicks DelayTimerBase::Now() const {
Patrick Monettec4d306d2021-06-23 19:15:25130 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Patrick Monette400b05142021-04-21 22:28:35131 return tick_clock_ ? tick_clock_->NowTicks() : TimeTicks::Now();
132}
133
Etienne Pierre-doray9c3d17d82022-05-12 22:05:29134void DelayTimerBase::OnScheduledTaskInvoked() {
Patrick Monettec4d306d2021-06-23 19:15:25135 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Etienne Pierre-doray9c3d17d82022-05-12 22:05:29136 DCHECK(!delayed_task_handle_.IsValid()) << posted_from_.ToString();
Patrick Monette57d1c18d2021-04-22 00:50:44137
tzikf3336c92018-07-25 03:15:50138 RunUserTask();
gab4e844bb2017-06-01 16:23:36139 // No more member accesses here: |this| could be deleted at this point.
initial.commitd7cae122008-07-26 21:49:38140}
141
tzikd93bb0862018-07-19 11:54:14142} // namespace internal
143
tzikf3336c92018-07-25 03:15:50144OneShotTimer::OneShotTimer() = default;
145OneShotTimer::OneShotTimer(const TickClock* tick_clock)
Etienne Pierre-doray1a0edc72022-01-14 15:11:44146 : internal::DelayTimerBase(tick_clock) {}
tzikf3336c92018-07-25 03:15:50147OneShotTimer::~OneShotTimer() = default;
148
149void OneShotTimer::Start(const Location& posted_from,
150 TimeDelta delay,
151 OnceClosure user_task) {
152 user_task_ = std::move(user_task);
153 StartInternal(posted_from, delay);
154}
155
tzikf550a612018-07-12 02:25:34156void OneShotTimer::FireNow() {
Patrick Monettec4d306d2021-06-23 19:15:25157 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tzikf550a612018-07-12 02:25:34158 DCHECK(!task_runner_) << "FireNow() is incompatible with SetTaskRunner()";
159 DCHECK(IsRunning());
160
tzikf3336c92018-07-25 03:15:50161 RunUserTask();
162}
163
164void OneShotTimer::OnStop() {
165 user_task_.Reset();
166 // No more member accesses here: |this| could be deleted after freeing
167 // |user_task_|.
168}
169
170void OneShotTimer::RunUserTask() {
171 // Make a local copy of the task to run. The Stop method will reset the
172 // |user_task_| member.
173 OnceClosure task = std::move(user_task_);
tzikf550a612018-07-12 02:25:34174 Stop();
tzikf3336c92018-07-25 03:15:50175 DCHECK(task);
tzikf550a612018-07-12 02:25:34176 std::move(task).Run();
tzikf3336c92018-07-25 03:15:50177 // No more member accesses here: |this| could be deleted at this point.
178}
179
Patrick Monette478af572022-01-20 20:34:15180void OneShotTimer::EnsureNonNullUserTask() {
Daniel Andersson4f49bc32024-06-26 19:29:18181 CHECK(user_task_);
Patrick Monette478af572022-01-20 20:34:15182}
183
tzikf3336c92018-07-25 03:15:50184RepeatingTimer::RepeatingTimer() = default;
185RepeatingTimer::RepeatingTimer(const TickClock* tick_clock)
Etienne Pierre-doray1a0edc72022-01-14 15:11:44186 : internal::DelayTimerBase(tick_clock) {}
tzikf3336c92018-07-25 03:15:50187RepeatingTimer::~RepeatingTimer() = default;
188
189RepeatingTimer::RepeatingTimer(const Location& posted_from,
190 TimeDelta delay,
191 RepeatingClosure user_task)
Etienne Pierre-doray1a0edc72022-01-14 15:11:44192 : internal::DelayTimerBase(posted_from, delay),
tzikf3336c92018-07-25 03:15:50193 user_task_(std::move(user_task)) {}
194RepeatingTimer::RepeatingTimer(const Location& posted_from,
195 TimeDelta delay,
196 RepeatingClosure user_task,
197 const TickClock* tick_clock)
Etienne Pierre-doray1a0edc72022-01-14 15:11:44198 : internal::DelayTimerBase(posted_from, delay, tick_clock),
tzikf3336c92018-07-25 03:15:50199 user_task_(std::move(user_task)) {}
200
201void RepeatingTimer::Start(const Location& posted_from,
202 TimeDelta delay,
203 RepeatingClosure user_task) {
204 user_task_ = std::move(user_task);
205 StartInternal(posted_from, delay);
206}
207
208void RepeatingTimer::OnStop() {}
Etienne Pierre-doray8c6860d2023-03-22 20:18:49209
tzikf3336c92018-07-25 03:15:50210void RepeatingTimer::RunUserTask() {
211 // Make a local copy of the task to run in case the task destroy the timer
212 // instance.
213 RepeatingClosure task = user_task_;
Patrick Monette57d1c18d2021-04-22 00:50:44214 ScheduleNewTask(GetCurrentDelay());
tzikf3336c92018-07-25 03:15:50215 task.Run();
216 // No more member accesses here: |this| could be deleted at this point.
217}
218
Patrick Monette478af572022-01-20 20:34:15219void RepeatingTimer::EnsureNonNullUserTask() {
220 DCHECK(user_task_);
221}
222
tzikf3336c92018-07-25 03:15:50223RetainingOneShotTimer::RetainingOneShotTimer() = default;
224RetainingOneShotTimer::RetainingOneShotTimer(const TickClock* tick_clock)
Etienne Pierre-doray1a0edc72022-01-14 15:11:44225 : internal::DelayTimerBase(tick_clock) {}
tzikf3336c92018-07-25 03:15:50226RetainingOneShotTimer::~RetainingOneShotTimer() = default;
227
228RetainingOneShotTimer::RetainingOneShotTimer(const Location& posted_from,
229 TimeDelta delay,
230 RepeatingClosure user_task)
Etienne Pierre-doray1a0edc72022-01-14 15:11:44231 : internal::DelayTimerBase(posted_from, delay),
tzikf3336c92018-07-25 03:15:50232 user_task_(std::move(user_task)) {}
233RetainingOneShotTimer::RetainingOneShotTimer(const Location& posted_from,
234 TimeDelta delay,
235 RepeatingClosure user_task,
236 const TickClock* tick_clock)
Etienne Pierre-doray1a0edc72022-01-14 15:11:44237 : internal::DelayTimerBase(posted_from, delay, tick_clock),
tzikf3336c92018-07-25 03:15:50238 user_task_(std::move(user_task)) {}
239
240void RetainingOneShotTimer::Start(const Location& posted_from,
241 TimeDelta delay,
242 RepeatingClosure user_task) {
243 user_task_ = std::move(user_task);
244 StartInternal(posted_from, delay);
245}
246
247void RetainingOneShotTimer::OnStop() {}
Etienne Pierre-doray8c6860d2023-03-22 20:18:49248
tzikf3336c92018-07-25 03:15:50249void RetainingOneShotTimer::RunUserTask() {
250 // Make a local copy of the task to run in case the task destroys the timer
251 // instance.
252 RepeatingClosure task = user_task_;
253 Stop();
254 task.Run();
255 // No more member accesses here: |this| could be deleted at this point.
tzikf550a612018-07-12 02:25:34256}
257
Patrick Monette478af572022-01-20 20:34:15258void RetainingOneShotTimer::EnsureNonNullUserTask() {
259 DCHECK(user_task_);
260}
261
Etienne Pierre-doray1a0edc72022-01-14 15:11:44262DeadlineTimer::DeadlineTimer() = default;
263DeadlineTimer::~DeadlineTimer() = default;
264
265void DeadlineTimer::Start(const Location& posted_from,
266 TimeTicks deadline,
267 OnceClosure user_task,
Etienne Pierre-doraya3f38272022-12-08 22:10:51268 subtle::DelayPolicy delay_policy) {
Etienne Pierre-doray1a0edc72022-01-14 15:11:44269 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Etienne Pierre-dorayfeab1c22022-12-01 15:31:05270 AbandonScheduledTask();
Etienne Pierre-doray1a0edc72022-01-14 15:11:44271 user_task_ = std::move(user_task);
272 posted_from_ = posted_from;
Etienne Pierre-doray1a0edc72022-01-14 15:11:44273 ScheduleNewTask(deadline, delay_policy);
274}
275
276void DeadlineTimer::OnStop() {
277 user_task_.Reset();
278 // No more member accesses here: |this| could be deleted after freeing
279 // |user_task_|.
280}
281
Etienne Pierre-doray9c3d17d82022-05-12 22:05:29282void DeadlineTimer::ScheduleNewTask(TimeTicks deadline,
283 subtle::DelayPolicy delay_policy) {
284 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Etienne Pierre-doray9c3d17d82022-05-12 22:05:29285
Etienne Pierre-dorayf16856862022-06-10 18:49:02286 if (!timer_callback_) {
287 timer_callback_ =
288 BindRepeating(&DeadlineTimer::OnScheduledTaskInvoked, Unretained(this));
289 }
Etienne Pierre-doray9c3d17d82022-05-12 22:05:29290 delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTaskAt(
Etienne Pierre-dorayf16856862022-06-10 18:49:02291 base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_,
Etienne Pierre-doray9c3d17d82022-05-12 22:05:29292 deadline, delay_policy);
293}
294
295void DeadlineTimer::OnScheduledTaskInvoked() {
296 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
297 DCHECK(!delayed_task_handle_.IsValid());
298
Etienne Pierre-doray1a0edc72022-01-14 15:11:44299 // Make a local copy of the task to run. The Stop method will reset the
300 // |user_task_| member.
301 OnceClosure task = std::move(user_task_);
302 Stop();
303 std::move(task).Run();
304 // No more member accesses here: |this| could be deleted at this point.
305}
306
Etienne Pierre-dorayc7654612022-06-08 22:23:32307MetronomeTimer::MetronomeTimer() = default;
308MetronomeTimer::~MetronomeTimer() = default;
309
310MetronomeTimer::MetronomeTimer(const Location& posted_from,
311 TimeDelta interval,
312 RepeatingClosure user_task,
313 TimeTicks phase)
314 : TimerBase(posted_from),
315 interval_(interval),
316 user_task_(user_task),
317 phase_(phase) {}
318
319void MetronomeTimer::Start(const Location& posted_from,
320 TimeDelta interval,
321 RepeatingClosure user_task,
322 TimeTicks phase) {
323 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
324 user_task_ = std::move(user_task);
325 posted_from_ = posted_from;
326 interval_ = interval;
327 phase_ = phase;
328
329 Reset();
330}
331
332void MetronomeTimer::OnStop() {
333 user_task_.Reset();
334 // No more member accesses here: |this| could be deleted after freeing
335 // |user_task_|.
336}
337
338void MetronomeTimer::Reset() {
339 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
340 DCHECK(user_task_);
341 // We can't reuse the |scheduled_task_|, so abandon it and post a new one.
342 AbandonScheduledTask();
343 ScheduleNewTask();
344}
345
346void MetronomeTimer::ScheduleNewTask() {
347 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Etienne Pierre-dorayc7654612022-06-08 22:23:32348
349 // The next wake up is scheduled at the next aligned time which is at least
350 // `interval_ / 2` after now. `interval_ / 2` is added to avoid playing
351 // "catch-up" if wake ups are late.
352 TimeTicks deadline =
353 (TimeTicks::Now() + interval_ / 2).SnappedToNextTick(phase_, interval_);
354
Etienne Pierre-dorayf16856862022-06-10 18:49:02355 if (!timer_callback_) {
356 timer_callback_ = BindRepeating(&MetronomeTimer::OnScheduledTaskInvoked,
357 Unretained(this));
358 }
Etienne Pierre-dorayc7654612022-06-08 22:23:32359 delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTaskAt(
Etienne Pierre-dorayf16856862022-06-10 18:49:02360 base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_,
Etienne Pierre-dorayc7654612022-06-08 22:23:32361 deadline, subtle::DelayPolicy::kPrecise);
362}
363
364void MetronomeTimer::OnScheduledTaskInvoked() {
365 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
366 DCHECK(!delayed_task_handle_.IsValid());
367
368 // Make a local copy of the task to run in case the task destroy the timer
369 // instance.
370 RepeatingClosure task = user_task_;
371 ScheduleNewTask();
372 std::move(task).Run();
373 // No more member accesses here: |this| could be deleted at this point.
374}
375
[email protected]aeab57ea2008-08-28 20:50:12376} // namespace base