| 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 |