• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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