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 #include "base/timer/timer.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10
11 #include "base/check.h"
12 #include "base/feature_list.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/memory/raw_ptr_exclusion.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/task/sequenced_task_runner.h"
17 #include "base/task/task_features.h"
18 #include "base/threading/platform_thread.h"
19 #include "base/time/tick_clock.h"
20
21 namespace base {
22 namespace internal {
23
TimerBase(const Location & posted_from)24 TimerBase::TimerBase(const Location& posted_from) : posted_from_(posted_from) {
25 // 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.
29 DETACH_FROM_SEQUENCE(sequence_checker_);
30 }
31
~TimerBase()32 TimerBase::~TimerBase() {
33 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
34 AbandonScheduledTask();
35 }
36
IsRunning() const37 bool TimerBase::IsRunning() const {
38 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
39 return delayed_task_handle_.IsValid();
40 }
41
SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner)42 void TimerBase::SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) {
43 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
44 DCHECK(task_runner->RunsTasksInCurrentSequence());
45 DCHECK(!IsRunning());
46 task_runner_.swap(task_runner);
47 }
48
GetTaskRunner()49 scoped_refptr<SequencedTaskRunner> TimerBase::GetTaskRunner() {
50 return task_runner_ ? task_runner_ : SequencedTaskRunner::GetCurrentDefault();
51 }
52
Stop()53 void TimerBase::Stop() {
54 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
55
56 AbandonScheduledTask();
57
58 OnStop();
59 // No more member accesses here: |this| could be deleted after Stop() call.
60 }
61
AbandonScheduledTask()62 void TimerBase::AbandonScheduledTask() {
63 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
64
65 if (delayed_task_handle_.IsValid())
66 delayed_task_handle_.CancelTask();
67
68 // It's safe to destroy or restart Timer on another sequence after the task is
69 // abandoned.
70 DETACH_FROM_SEQUENCE(sequence_checker_);
71 }
72
DelayTimerBase(const TickClock * tick_clock)73 DelayTimerBase::DelayTimerBase(const TickClock* tick_clock)
74 : tick_clock_(tick_clock) {}
75
DelayTimerBase(const Location & posted_from,TimeDelta delay,const TickClock * tick_clock)76 DelayTimerBase::DelayTimerBase(const Location& posted_from,
77 TimeDelta delay,
78 const TickClock* tick_clock)
79 : TimerBase(posted_from), delay_(delay), tick_clock_(tick_clock) {}
80
81 DelayTimerBase::~DelayTimerBase() = default;
82
GetCurrentDelay() const83 TimeDelta DelayTimerBase::GetCurrentDelay() const {
84 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
85 return delay_;
86 }
87
StartInternal(const Location & posted_from,TimeDelta delay)88 void DelayTimerBase::StartInternal(const Location& posted_from,
89 TimeDelta delay) {
90 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
91
92 posted_from_ = posted_from;
93 delay_ = delay;
94
95 Reset();
96 }
97
Reset()98 void DelayTimerBase::Reset() {
99 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
100
101 EnsureNonNullUserTask();
102
103 // We can't reuse the |scheduled_task_|, so abandon it and post a new one.
104 AbandonScheduledTask();
105 ScheduleNewTask(delay_);
106 }
107
ScheduleNewTask(TimeDelta delay)108 void DelayTimerBase::ScheduleNewTask(TimeDelta delay) {
109 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
110 DCHECK(!delayed_task_handle_.IsValid());
111
112 // Ignore negative deltas.
113 // TODO(pmonette): Fix callers providing negative deltas and ban passing them.
114 if (delay < TimeDelta())
115 delay = TimeDelta();
116
117 if (!timer_callback_) {
118 timer_callback_ = BindRepeating(&DelayTimerBase::OnScheduledTaskInvoked,
119 Unretained(this));
120 }
121 delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTask(
122 base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_,
123 delay);
124 desired_run_time_ = Now() + delay;
125 }
126
Now() const127 TimeTicks DelayTimerBase::Now() const {
128 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
129 return tick_clock_ ? tick_clock_->NowTicks() : TimeTicks::Now();
130 }
131
OnScheduledTaskInvoked()132 void DelayTimerBase::OnScheduledTaskInvoked() {
133 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
134 DCHECK(!delayed_task_handle_.IsValid()) << posted_from_.ToString();
135
136 RunUserTask();
137 // No more member accesses here: |this| could be deleted at this point.
138 }
139
140 } // namespace internal
141
142 OneShotTimer::OneShotTimer() = default;
OneShotTimer(const TickClock * tick_clock)143 OneShotTimer::OneShotTimer(const TickClock* tick_clock)
144 : internal::DelayTimerBase(tick_clock) {}
145 OneShotTimer::~OneShotTimer() = default;
146
Start(const Location & posted_from,TimeDelta delay,OnceClosure user_task)147 void OneShotTimer::Start(const Location& posted_from,
148 TimeDelta delay,
149 OnceClosure user_task) {
150 user_task_ = std::move(user_task);
151 StartInternal(posted_from, delay);
152 }
153
FireNow()154 void OneShotTimer::FireNow() {
155 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
156 DCHECK(!task_runner_) << "FireNow() is incompatible with SetTaskRunner()";
157 DCHECK(IsRunning());
158
159 RunUserTask();
160 }
161
OnStop()162 void OneShotTimer::OnStop() {
163 user_task_.Reset();
164 // No more member accesses here: |this| could be deleted after freeing
165 // |user_task_|.
166 }
167
RunUserTask()168 void OneShotTimer::RunUserTask() {
169 // Make a local copy of the task to run. The Stop method will reset the
170 // |user_task_| member.
171 OnceClosure task = std::move(user_task_);
172 Stop();
173 DCHECK(task);
174 std::move(task).Run();
175 // No more member accesses here: |this| could be deleted at this point.
176 }
177
EnsureNonNullUserTask()178 void OneShotTimer::EnsureNonNullUserTask() {
179 CHECK(user_task_);
180 }
181
182 RepeatingTimer::RepeatingTimer() = default;
RepeatingTimer(const TickClock * tick_clock)183 RepeatingTimer::RepeatingTimer(const TickClock* tick_clock)
184 : internal::DelayTimerBase(tick_clock) {}
185 RepeatingTimer::~RepeatingTimer() = default;
186
RepeatingTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task)187 RepeatingTimer::RepeatingTimer(const Location& posted_from,
188 TimeDelta delay,
189 RepeatingClosure user_task)
190 : internal::DelayTimerBase(posted_from, delay),
191 user_task_(std::move(user_task)) {}
RepeatingTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task,const TickClock * tick_clock)192 RepeatingTimer::RepeatingTimer(const Location& posted_from,
193 TimeDelta delay,
194 RepeatingClosure user_task,
195 const TickClock* tick_clock)
196 : internal::DelayTimerBase(posted_from, delay, tick_clock),
197 user_task_(std::move(user_task)) {}
198
Start(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task)199 void RepeatingTimer::Start(const Location& posted_from,
200 TimeDelta delay,
201 RepeatingClosure user_task) {
202 user_task_ = std::move(user_task);
203 StartInternal(posted_from, delay);
204 }
205
OnStop()206 void RepeatingTimer::OnStop() {}
207
RunUserTask()208 void RepeatingTimer::RunUserTask() {
209 // Make a local copy of the task to run in case the task destroy the timer
210 // instance.
211 RepeatingClosure task = user_task_;
212 ScheduleNewTask(GetCurrentDelay());
213 task.Run();
214 // No more member accesses here: |this| could be deleted at this point.
215 }
216
EnsureNonNullUserTask()217 void RepeatingTimer::EnsureNonNullUserTask() {
218 DCHECK(user_task_);
219 }
220
221 RetainingOneShotTimer::RetainingOneShotTimer() = default;
RetainingOneShotTimer(const TickClock * tick_clock)222 RetainingOneShotTimer::RetainingOneShotTimer(const TickClock* tick_clock)
223 : internal::DelayTimerBase(tick_clock) {}
224 RetainingOneShotTimer::~RetainingOneShotTimer() = default;
225
RetainingOneShotTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task)226 RetainingOneShotTimer::RetainingOneShotTimer(const Location& posted_from,
227 TimeDelta delay,
228 RepeatingClosure user_task)
229 : internal::DelayTimerBase(posted_from, delay),
230 user_task_(std::move(user_task)) {}
RetainingOneShotTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task,const TickClock * tick_clock)231 RetainingOneShotTimer::RetainingOneShotTimer(const Location& posted_from,
232 TimeDelta delay,
233 RepeatingClosure user_task,
234 const TickClock* tick_clock)
235 : internal::DelayTimerBase(posted_from, delay, tick_clock),
236 user_task_(std::move(user_task)) {}
237
Start(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task)238 void RetainingOneShotTimer::Start(const Location& posted_from,
239 TimeDelta delay,
240 RepeatingClosure user_task) {
241 user_task_ = std::move(user_task);
242 StartInternal(posted_from, delay);
243 }
244
OnStop()245 void RetainingOneShotTimer::OnStop() {}
246
RunUserTask()247 void RetainingOneShotTimer::RunUserTask() {
248 // Make a local copy of the task to run in case the task destroys the timer
249 // instance.
250 RepeatingClosure task = user_task_;
251 Stop();
252 task.Run();
253 // No more member accesses here: |this| could be deleted at this point.
254 }
255
EnsureNonNullUserTask()256 void RetainingOneShotTimer::EnsureNonNullUserTask() {
257 DCHECK(user_task_);
258 }
259
260 DeadlineTimer::DeadlineTimer() = default;
261 DeadlineTimer::~DeadlineTimer() = default;
262
Start(const Location & posted_from,TimeTicks deadline,OnceClosure user_task,subtle::DelayPolicy delay_policy)263 void DeadlineTimer::Start(const Location& posted_from,
264 TimeTicks deadline,
265 OnceClosure user_task,
266 subtle::DelayPolicy delay_policy) {
267 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
268 AbandonScheduledTask();
269 user_task_ = std::move(user_task);
270 posted_from_ = posted_from;
271 ScheduleNewTask(deadline, delay_policy);
272 }
273
OnStop()274 void DeadlineTimer::OnStop() {
275 user_task_.Reset();
276 // No more member accesses here: |this| could be deleted after freeing
277 // |user_task_|.
278 }
279
ScheduleNewTask(TimeTicks deadline,subtle::DelayPolicy delay_policy)280 void DeadlineTimer::ScheduleNewTask(TimeTicks deadline,
281 subtle::DelayPolicy delay_policy) {
282 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
283
284 if (!timer_callback_) {
285 timer_callback_ =
286 BindRepeating(&DeadlineTimer::OnScheduledTaskInvoked, Unretained(this));
287 }
288 delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTaskAt(
289 base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_,
290 deadline, delay_policy);
291 }
292
OnScheduledTaskInvoked()293 void DeadlineTimer::OnScheduledTaskInvoked() {
294 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
295 DCHECK(!delayed_task_handle_.IsValid());
296
297 // Make a local copy of the task to run. The Stop method will reset the
298 // |user_task_| member.
299 OnceClosure task = std::move(user_task_);
300 Stop();
301 std::move(task).Run();
302 // No more member accesses here: |this| could be deleted at this point.
303 }
304
305 MetronomeTimer::MetronomeTimer() = default;
306 MetronomeTimer::~MetronomeTimer() = default;
307
MetronomeTimer(const Location & posted_from,TimeDelta interval,RepeatingClosure user_task,TimeTicks phase)308 MetronomeTimer::MetronomeTimer(const Location& posted_from,
309 TimeDelta interval,
310 RepeatingClosure user_task,
311 TimeTicks phase)
312 : TimerBase(posted_from),
313 interval_(interval),
314 user_task_(user_task),
315 phase_(phase) {}
316
Start(const Location & posted_from,TimeDelta interval,RepeatingClosure user_task,TimeTicks phase)317 void MetronomeTimer::Start(const Location& posted_from,
318 TimeDelta interval,
319 RepeatingClosure user_task,
320 TimeTicks phase) {
321 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
322 user_task_ = std::move(user_task);
323 posted_from_ = posted_from;
324 interval_ = interval;
325 phase_ = phase;
326
327 Reset();
328 }
329
OnStop()330 void MetronomeTimer::OnStop() {
331 user_task_.Reset();
332 // No more member accesses here: |this| could be deleted after freeing
333 // |user_task_|.
334 }
335
Reset()336 void MetronomeTimer::Reset() {
337 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
338 DCHECK(user_task_);
339 // We can't reuse the |scheduled_task_|, so abandon it and post a new one.
340 AbandonScheduledTask();
341 ScheduleNewTask();
342 }
343
ScheduleNewTask()344 void MetronomeTimer::ScheduleNewTask() {
345 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
346
347 // The next wake up is scheduled at the next aligned time which is at least
348 // `interval_ / 2` after now. `interval_ / 2` is added to avoid playing
349 // "catch-up" if wake ups are late.
350 TimeTicks deadline =
351 (TimeTicks::Now() + interval_ / 2).SnappedToNextTick(phase_, interval_);
352
353 if (!timer_callback_) {
354 timer_callback_ = BindRepeating(&MetronomeTimer::OnScheduledTaskInvoked,
355 Unretained(this));
356 }
357 delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTaskAt(
358 base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_,
359 deadline, subtle::DelayPolicy::kPrecise);
360 }
361
OnScheduledTaskInvoked()362 void MetronomeTimer::OnScheduledTaskInvoked() {
363 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
364 DCHECK(!delayed_task_handle_.IsValid());
365
366 // Make a local copy of the task to run in case the task destroy the timer
367 // instance.
368 RepeatingClosure task = user_task_;
369 ScheduleNewTask();
370 std::move(task).Run();
371 // No more member accesses here: |this| could be deleted at this point.
372 }
373
374 } // namespace base
375