OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 | |
5 #include "sky/scheduler/timer.h" | |
6 | |
7 #include <cstdlib> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/tracked_objects.h" | |
11 | |
12 namespace sky { | |
13 | |
14 // We're willing to slop around 1/4 of a tick duration to avoid trashing our | |
15 // client with irregular ticks. | |
16 static const int64 kTickSlop = 4; | |
17 | |
18 Timer::Client::~Client() { | |
19 } | |
20 | |
21 Timer::Timer(Client* client, | |
22 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | |
23 : client_(client), | |
24 task_runner_(task_runner), | |
25 enabled_(false), | |
26 weak_factory_(this) { | |
27 DCHECK(client_); | |
28 } | |
29 | |
30 Timer::~Timer() { | |
31 } | |
32 | |
33 void Timer::SetEnabled(bool enabled) { | |
34 enabled_ = enabled; | |
35 | |
36 if (enabled_ && current_target_.is_null()) | |
37 ScheduleNextTick(base::TimeTicks::Now()); | |
38 } | |
39 | |
40 void Timer::SetInterval(const TimeInterval& interval) { | |
41 interval_ = interval; | |
42 | |
43 // We don't have a tick scheduled, so there's no need to reschedule it. | |
44 if (current_target_.is_null()) | |
45 return; | |
46 | |
47 base::TimeTicks now = base::TimeTicks::Now(); | |
48 | |
49 base::TimeTicks new_target = NextTickTarget(now); | |
50 base::TimeDelta delta = base::TimeDelta::FromInternalValue( | |
51 std::abs((new_target - current_target_).ToInternalValue())); | |
52 | |
53 if (delta * kTickSlop < interval_.duration) | |
54 return; | |
55 | |
56 current_target_ = base::TimeTicks(); | |
57 weak_factory_.InvalidateWeakPtrs(); | |
58 PostTickTask(now, new_target); | |
59 } | |
60 | |
61 base::TimeTicks Timer::NextTickTarget(base::TimeTicks now) { | |
62 base::TimeTicks target = interval_.NextAfter(now); | |
63 | |
64 // If we're targeting a time that's too soon since the last tick, we push out | |
65 // the target to the next tick. | |
66 if ((target - last_tick_) * kTickSlop < interval_.duration) | |
67 target += interval_.duration; | |
68 | |
69 return target; | |
70 } | |
71 | |
72 void Timer::ScheduleNextTick(base::TimeTicks now) { | |
73 PostTickTask(now, NextTickTarget(now)); | |
74 } | |
75 | |
76 void Timer::PostTickTask(base::TimeTicks now, base::TimeTicks target) { | |
77 DCHECK(current_target_.is_null()); | |
78 current_target_ = target; | |
79 task_runner_->PostDelayedTask( | |
80 FROM_HERE, base::Bind(&Timer::OnTimerFired, weak_factory_.GetWeakPtr()), | |
81 current_target_ - now); | |
82 } | |
83 | |
84 void Timer::OnTimerFired() { | |
85 current_target_ = base::TimeTicks(); | |
86 if (!enabled_) | |
87 return; | |
88 base::TimeTicks now = base::TimeTicks::Now(); | |
89 ScheduleNextTick(now); | |
90 last_tick_ = now; | |
91 client_->OnTimerTick(now); | |
92 // We might be deleted here. | |
93 } | |
94 } | |
OLD | NEW |