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
AbandonAndStop()98 void DelayTimerBase::AbandonAndStop() {
99 Stop();
100 }
101
Reset()102 void DelayTimerBase::Reset() {
103 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
104
105 EnsureNonNullUserTask();
106
107 // We can't reuse the |scheduled_task_|, so abandon it and post a new one.
108 AbandonScheduledTask();
109 ScheduleNewTask(delay_);
110 }
111
ScheduleNewTask(TimeDelta delay)112 void DelayTimerBase::ScheduleNewTask(TimeDelta delay) {
113 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
114 DCHECK(!delayed_task_handle_.IsValid());
115
116 // Ignore negative deltas.
117 // TODO(pmonette): Fix callers providing negative deltas and ban passing them.
118 if (delay < TimeDelta())
119 delay = TimeDelta();
120
121 if (!timer_callback_) {
122 timer_callback_ = BindRepeating(&DelayTimerBase::OnScheduledTaskInvoked,
123 Unretained(this));
124 }
125 delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTask(
126 base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_,
127 delay);
128 desired_run_time_ = Now() + delay;
129 }
130
Now() const131 TimeTicks DelayTimerBase::Now() const {
132 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
133 return tick_clock_ ? tick_clock_->NowTicks() : TimeTicks::Now();
134 }
135
OnScheduledTaskInvoked()136 void DelayTimerBase::OnScheduledTaskInvoked() {
137 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
138 DCHECK(!delayed_task_handle_.IsValid()) << posted_from_.ToString();
139
140 RunUserTask();
141 // No more member accesses here: |this| could be deleted at this point.
142 }
143
144 } // namespace internal
145
146 OneShotTimer::OneShotTimer() = default;
OneShotTimer(const TickClock * tick_clock)147 OneShotTimer::OneShotTimer(const TickClock* tick_clock)
148 : internal::DelayTimerBase(tick_clock) {}
149 OneShotTimer::~OneShotTimer() = default;
150
Start(const Location & posted_from,TimeDelta delay,OnceClosure user_task)151 void OneShotTimer::Start(const Location& posted_from,
152 TimeDelta delay,
153 OnceClosure user_task) {
154 user_task_ = std::move(user_task);
155 StartInternal(posted_from, delay);
156 }
157
FireNow()158 void OneShotTimer::FireNow() {
159 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
160 DCHECK(!task_runner_) << "FireNow() is incompatible with SetTaskRunner()";
161 DCHECK(IsRunning());
162
163 RunUserTask();
164 }
165
OnStop()166 void OneShotTimer::OnStop() {
167 user_task_.Reset();
168 // No more member accesses here: |this| could be deleted after freeing
169 // |user_task_|.
170 }
171
RunUserTask()172 void OneShotTimer::RunUserTask() {
173 // Make a local copy of the task to run. The Stop method will reset the
174 // |user_task_| member.
175 OnceClosure task = std::move(user_task_);
176 Stop();
177 DCHECK(task);
178 std::move(task).Run();
179 // No more member accesses here: |this| could be deleted at this point.
180 }
181
EnsureNonNullUserTask()182 void OneShotTimer::EnsureNonNullUserTask() {
183 DCHECK(user_task_);
184 }
185
186 RepeatingTimer::RepeatingTimer() = default;
RepeatingTimer(const TickClock * tick_clock)187 RepeatingTimer::RepeatingTimer(const TickClock* tick_clock)
188 : internal::DelayTimerBase(tick_clock) {}
189 RepeatingTimer::~RepeatingTimer() = default;
190
RepeatingTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task)191 RepeatingTimer::RepeatingTimer(const Location& posted_from,
192 TimeDelta delay,
193 RepeatingClosure user_task)
194 : internal::DelayTimerBase(posted_from, delay),
195 user_task_(std::move(user_task)) {}
RepeatingTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task,const TickClock * tick_clock)196 RepeatingTimer::RepeatingTimer(const Location& posted_from,
197 TimeDelta delay,
198 RepeatingClosure user_task,
199 const TickClock* tick_clock)
200 : internal::DelayTimerBase(posted_from, delay, tick_clock),
201 user_task_(std::move(user_task)) {}
202
Start(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task)203 void RepeatingTimer::Start(const Location& posted_from,
204 TimeDelta delay,
205 RepeatingClosure user_task) {
206 user_task_ = std::move(user_task);
207 StartInternal(posted_from, delay);
208 }
209
OnStop()210 void RepeatingTimer::OnStop() {}
211
RunUserTask()212 void RepeatingTimer::RunUserTask() {
213 // Make a local copy of the task to run in case the task destroy the timer
214 // instance.
215 RepeatingClosure task = user_task_;
216 ScheduleNewTask(GetCurrentDelay());
217 task.Run();
218 // No more member accesses here: |this| could be deleted at this point.
219 }
220
EnsureNonNullUserTask()221 void RepeatingTimer::EnsureNonNullUserTask() {
222 DCHECK(user_task_);
223 }
224
225 RetainingOneShotTimer::RetainingOneShotTimer() = default;
RetainingOneShotTimer(const TickClock * tick_clock)226 RetainingOneShotTimer::RetainingOneShotTimer(const TickClock* tick_clock)
227 : internal::DelayTimerBase(tick_clock) {}
228 RetainingOneShotTimer::~RetainingOneShotTimer() = default;
229
RetainingOneShotTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task)230 RetainingOneShotTimer::RetainingOneShotTimer(const Location& posted_from,
231 TimeDelta delay,
232 RepeatingClosure user_task)
233 : internal::DelayTimerBase(posted_from, delay),
234 user_task_(std::move(user_task)) {}
RetainingOneShotTimer(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task,const TickClock * tick_clock)235 RetainingOneShotTimer::RetainingOneShotTimer(const Location& posted_from,
236 TimeDelta delay,
237 RepeatingClosure user_task,
238 const TickClock* tick_clock)
239 : internal::DelayTimerBase(posted_from, delay, tick_clock),
240 user_task_(std::move(user_task)) {}
241
Start(const Location & posted_from,TimeDelta delay,RepeatingClosure user_task)242 void RetainingOneShotTimer::Start(const Location& posted_from,
243 TimeDelta delay,
244 RepeatingClosure user_task) {
245 user_task_ = std::move(user_task);
246 StartInternal(posted_from, delay);
247 }
248
OnStop()249 void RetainingOneShotTimer::OnStop() {}
250
RunUserTask()251 void RetainingOneShotTimer::RunUserTask() {
252 // Make a local copy of the task to run in case the task destroys the timer
253 // instance.
254 RepeatingClosure task = user_task_;
255 Stop();
256 task.Run();
257 // No more member accesses here: |this| could be deleted at this point.
258 }
259
EnsureNonNullUserTask()260 void RetainingOneShotTimer::EnsureNonNullUserTask() {
261 DCHECK(user_task_);
262 }
263
264 DeadlineTimer::DeadlineTimer() = default;
265 DeadlineTimer::~DeadlineTimer() = default;
266
Start(const Location & posted_from,TimeTicks deadline,OnceClosure user_task,subtle::DelayPolicy delay_policy)267 void DeadlineTimer::Start(const Location& posted_from,
268 TimeTicks deadline,
269 OnceClosure user_task,
270 subtle::DelayPolicy delay_policy) {
271 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
272 AbandonScheduledTask();
273 user_task_ = std::move(user_task);
274 posted_from_ = posted_from;
275 ScheduleNewTask(deadline, delay_policy);
276 }
277
OnStop()278 void DeadlineTimer::OnStop() {
279 user_task_.Reset();
280 // No more member accesses here: |this| could be deleted after freeing
281 // |user_task_|.
282 }
283
ScheduleNewTask(TimeTicks deadline,subtle::DelayPolicy delay_policy)284 void DeadlineTimer::ScheduleNewTask(TimeTicks deadline,
285 subtle::DelayPolicy delay_policy) {
286 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
287
288 if (!timer_callback_) {
289 timer_callback_ =
290 BindRepeating(&DeadlineTimer::OnScheduledTaskInvoked, Unretained(this));
291 }
292 delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTaskAt(
293 base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_,
294 deadline, delay_policy);
295 }
296
OnScheduledTaskInvoked()297 void DeadlineTimer::OnScheduledTaskInvoked() {
298 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
299 DCHECK(!delayed_task_handle_.IsValid());
300
301 // Make a local copy of the task to run. The Stop method will reset the
302 // |user_task_| member.
303 OnceClosure task = std::move(user_task_);
304 Stop();
305 std::move(task).Run();
306 // No more member accesses here: |this| could be deleted at this point.
307 }
308
309 MetronomeTimer::MetronomeTimer() = default;
310 MetronomeTimer::~MetronomeTimer() = default;
311
MetronomeTimer(const Location & posted_from,TimeDelta interval,RepeatingClosure user_task,TimeTicks phase)312 MetronomeTimer::MetronomeTimer(const Location& posted_from,
313 TimeDelta interval,
314 RepeatingClosure user_task,
315 TimeTicks phase)
316 : TimerBase(posted_from),
317 interval_(interval),
318 user_task_(user_task),
319 phase_(phase) {}
320
Start(const Location & posted_from,TimeDelta interval,RepeatingClosure user_task,TimeTicks phase)321 void MetronomeTimer::Start(const Location& posted_from,
322 TimeDelta interval,
323 RepeatingClosure user_task,
324 TimeTicks phase) {
325 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
326 user_task_ = std::move(user_task);
327 posted_from_ = posted_from;
328 interval_ = interval;
329 phase_ = phase;
330
331 Reset();
332 }
333
OnStop()334 void MetronomeTimer::OnStop() {
335 user_task_.Reset();
336 // No more member accesses here: |this| could be deleted after freeing
337 // |user_task_|.
338 }
339
Reset()340 void MetronomeTimer::Reset() {
341 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
342 DCHECK(user_task_);
343 // We can't reuse the |scheduled_task_|, so abandon it and post a new one.
344 AbandonScheduledTask();
345 ScheduleNewTask();
346 }
347
ScheduleNewTask()348 void MetronomeTimer::ScheduleNewTask() {
349 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
350
351 // The next wake up is scheduled at the next aligned time which is at least
352 // `interval_ / 2` after now. `interval_ / 2` is added to avoid playing
353 // "catch-up" if wake ups are late.
354 TimeTicks deadline =
355 (TimeTicks::Now() + interval_ / 2).SnappedToNextTick(phase_, interval_);
356
357 if (!timer_callback_) {
358 timer_callback_ = BindRepeating(&MetronomeTimer::OnScheduledTaskInvoked,
359 Unretained(this));
360 }
361 delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTaskAt(
362 base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_,
363 deadline, subtle::DelayPolicy::kPrecise);
364 }
365
OnScheduledTaskInvoked()366 void MetronomeTimer::OnScheduledTaskInvoked() {
367 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
368 DCHECK(!delayed_task_handle_.IsValid());
369
370 // Make a local copy of the task to run in case the task destroy the timer
371 // instance.
372 RepeatingClosure task = user_task_;
373 ScheduleNewTask();
374 std::move(task).Run();
375 // No more member accesses here: |this| could be deleted at this point.
376 }
377
378 } // namespace base
379