OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/timer.h" | 5 #include "base/timer.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/message_loop.h" | 8 #include "base/single_thread_task_runner.h" |
| 9 #include "base/thread_task_runner_handle.h" |
| 10 #include "base/threading/platform_thread.h" |
9 | 11 |
10 namespace base { | 12 namespace base { |
11 | 13 |
12 // BaseTimerTaskInternal is a simple delegate for scheduling a callback to | 14 // BaseTimerTaskInternal is a simple delegate for scheduling a callback to |
13 // Timer in the MessageLoop. It also handles the following edge | 15 // Timer in the thread's default task runner. It also handles the following |
14 // cases: | 16 // edge cases: |
15 // - deleted by MessageLoop. | 17 // - deleted by the task runner. |
16 // - abandoned (orphaned) by Timer. | 18 // - abandoned (orphaned) by Timer. |
17 class BaseTimerTaskInternal { | 19 class BaseTimerTaskInternal { |
18 public: | 20 public: |
19 BaseTimerTaskInternal(Timer* timer) | 21 BaseTimerTaskInternal(Timer* timer) |
20 : timer_(timer) { | 22 : timer_(timer) { |
21 } | 23 } |
22 | 24 |
23 ~BaseTimerTaskInternal() { | 25 ~BaseTimerTaskInternal() { |
24 // This task may be getting cleared because the MessageLoop has been | 26 // This task may be getting cleared because the task runner has been |
25 // destructed. If so, don't leave Timer with a dangling pointer | 27 // destructed. If so, don't leave Timer with a dangling pointer |
26 // to this. | 28 // to this. |
27 if (timer_) | 29 if (timer_) |
28 timer_->StopAndAbandon(); | 30 timer_->StopAndAbandon(); |
29 } | 31 } |
30 | 32 |
31 void Run() { | 33 void Run() { |
32 // timer_ is NULL if we were abandoned. | 34 // timer_ is NULL if we were abandoned. |
33 if (!timer_) | 35 if (!timer_) |
34 return; | 36 return; |
35 | 37 |
36 // *this will be deleted by the MessageLoop, so Timer needs to | 38 // *this will be deleted by the task runner, so Timer needs to |
37 // forget us: | 39 // forget us: |
38 timer_->scheduled_task_ = NULL; | 40 timer_->scheduled_task_ = NULL; |
39 | 41 |
40 // Although Timer should not call back into *this, let's clear | 42 // Although Timer should not call back into *this, let's clear |
41 // the timer_ member first to be pedantic. | 43 // the timer_ member first to be pedantic. |
42 Timer* timer = timer_; | 44 Timer* timer = timer_; |
43 timer_ = NULL; | 45 timer_ = NULL; |
44 timer->RunScheduledTask(); | 46 timer->RunScheduledTask(); |
45 } | 47 } |
46 | 48 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 const base::Closure& user_task) { | 124 const base::Closure& user_task) { |
123 posted_from_ = posted_from; | 125 posted_from_ = posted_from; |
124 delay_ = delay; | 126 delay_ = delay; |
125 user_task_ = user_task; | 127 user_task_ = user_task; |
126 } | 128 } |
127 | 129 |
128 void Timer::PostNewScheduledTask(TimeDelta delay) { | 130 void Timer::PostNewScheduledTask(TimeDelta delay) { |
129 DCHECK(scheduled_task_ == NULL); | 131 DCHECK(scheduled_task_ == NULL); |
130 is_running_ = true; | 132 is_running_ = true; |
131 scheduled_task_ = new BaseTimerTaskInternal(this); | 133 scheduled_task_ = new BaseTimerTaskInternal(this); |
132 MessageLoop::current()->PostDelayedTask(posted_from_, | 134 ThreadTaskRunnerHandle::Get()->PostDelayedTask(posted_from_, |
133 base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)), | 135 base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)), |
134 delay); | 136 delay); |
135 scheduled_run_time_ = desired_run_time_ = TimeTicks::Now() + delay; | 137 scheduled_run_time_ = desired_run_time_ = TimeTicks::Now() + delay; |
136 // Remember the thread ID that posts the first task -- this will be verified | 138 // Remember the thread ID that posts the first task -- this will be verified |
137 // later when the task is abandoned to detect misuse from multiple threads. | 139 // later when the task is abandoned to detect misuse from multiple threads. |
138 if (!thread_id_) | 140 if (!thread_id_) |
139 thread_id_ = static_cast<int>(PlatformThread::CurrentId()); | 141 thread_id_ = static_cast<int>(PlatformThread::CurrentId()); |
140 } | 142 } |
141 | 143 |
142 void Timer::AbandonScheduledTask() { | 144 void Timer::AbandonScheduledTask() { |
143 DCHECK(thread_id_ == 0 || | 145 DCHECK(thread_id_ == 0 || |
144 thread_id_ == static_cast<int>(PlatformThread::CurrentId())); | 146 thread_id_ == static_cast<int>(PlatformThread::CurrentId())); |
145 if (scheduled_task_) { | 147 if (scheduled_task_) { |
146 scheduled_task_->Abandon(); | 148 scheduled_task_->Abandon(); |
147 scheduled_task_ = NULL; | 149 scheduled_task_ = NULL; |
148 } | 150 } |
149 } | 151 } |
150 | 152 |
151 void Timer::RunScheduledTask() { | 153 void Timer::RunScheduledTask() { |
152 // Task may have been disabled. | 154 // Task may have been disabled. |
153 if (!is_running_) | 155 if (!is_running_) |
154 return; | 156 return; |
155 | 157 |
156 // First check if we need to delay the task because of a new target time. | 158 // First check if we need to delay the task because of a new target time. |
157 if (desired_run_time_ > scheduled_run_time_) { | 159 if (desired_run_time_ > scheduled_run_time_) { |
158 // TimeTicks::Now() can be expensive, so only call it if we know the user | 160 // TimeTicks::Now() can be expensive, so only call it if we know the user |
159 // has changed the desired_run_time_. | 161 // has changed the desired_run_time_. |
160 TimeTicks now = TimeTicks::Now(); | 162 TimeTicks now = TimeTicks::Now(); |
161 // MessageLoop may have called us late anyway, so only post a continuation | 163 // Task runner may have called us late anyway, so only post a continuation |
162 // task if the desired_run_time_ is in the future. | 164 // task if the desired_run_time_ is in the future. |
163 if (desired_run_time_ > now) { | 165 if (desired_run_time_ > now) { |
164 // Post a new task to span the remaining time. | 166 // Post a new task to span the remaining time. |
165 PostNewScheduledTask(desired_run_time_ - now); | 167 PostNewScheduledTask(desired_run_time_ - now); |
166 return; | 168 return; |
167 } | 169 } |
168 } | 170 } |
169 | 171 |
170 // Make a local copy of the task to run. The Stop method will reset the | 172 // Make a local copy of the task to run. The Stop method will reset the |
171 // user_task_ member if retain_user_task_ is false. | 173 // user_task_ member if retain_user_task_ is false. |
172 base::Closure task = user_task_; | 174 base::Closure task = user_task_; |
173 | 175 |
174 if (is_repeating_) | 176 if (is_repeating_) |
175 PostNewScheduledTask(delay_); | 177 PostNewScheduledTask(delay_); |
176 else | 178 else |
177 Stop(); | 179 Stop(); |
178 | 180 |
179 task.Run(); | 181 task.Run(); |
180 | 182 |
181 // No more member accesses here: *this could be deleted at this point. | 183 // No more member accesses here: *this could be deleted at this point. |
182 } | 184 } |
183 | 185 |
184 } // namespace base | 186 } // namespace base |
OLD | NEW |