Chromium Code Reviews| 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/run_loop.h" | 5 #include "base/run_loop.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback.h" | |
| 8 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/single_thread_task_runner.h" | |
| 9 #include "base/threading/thread_local.h" | 11 #include "base/threading/thread_local.h" |
| 12 #include "base/threading/thread_task_runner_handle.h" | |
| 10 #include "base/tracked_objects.h" | 13 #include "base/tracked_objects.h" |
| 11 #include "build/build_config.h" | 14 #include "build/build_config.h" |
| 12 | 15 |
| 13 namespace base { | 16 namespace base { |
| 14 | 17 |
| 15 namespace { | 18 namespace { |
| 16 | 19 |
| 17 LazyInstance<ThreadLocalPointer<RunLoop::Delegate>>::Leaky tls_delegate = | 20 LazyInstance<ThreadLocalPointer<RunLoop::Delegate>>::Leaky tls_delegate = |
| 18 LAZY_INSTANCE_INITIALIZER; | 21 LAZY_INSTANCE_INITIALIZER; |
| 19 | 22 |
| 23 // Runs |closure| immediately if this is called on |task_runner|, otherwise | |
| 24 // forwards |closure| to it. | |
| 25 void ProxyToTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner, | |
| 26 OnceClosure closure) { | |
| 27 if (task_runner->RunsTasksInCurrentSequence()) { | |
|
danakj
2017/05/19 18:11:30
This if (on thread) A else post A pattern always i
gab
2017/05/19 19:38:16
Discussed offline, won't do that because the goal
| |
| 28 std::move(closure).Run(); | |
| 29 return; | |
| 30 } | |
| 31 task_runner->PostTask(FROM_HERE, std::move(closure)); | |
| 32 } | |
| 33 | |
| 20 } // namespace | 34 } // namespace |
| 21 | 35 |
| 22 RunLoop::Delegate::Delegate() { | 36 RunLoop::Delegate::Delegate() { |
| 23 // The Delegate can be created on another thread. It is only bound in | 37 // The Delegate can be created on another thread. It is only bound in |
| 24 // RegisterDelegateForCurrentThread(). | 38 // RegisterDelegateForCurrentThread(). |
| 25 DETACH_FROM_THREAD(bound_thread_checker_); | 39 DETACH_FROM_THREAD(bound_thread_checker_); |
| 26 } | 40 } |
| 27 | 41 |
| 28 RunLoop::Delegate::~Delegate() { | 42 RunLoop::Delegate::~Delegate() { |
| 29 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); | 43 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 56 DCHECK_CALLED_ON_VALID_THREAD(delegate->bound_thread_checker_); | 70 DCHECK_CALLED_ON_VALID_THREAD(delegate->bound_thread_checker_); |
| 57 | 71 |
| 58 // There can only be one RunLoop::Delegate per thread. | 72 // There can only be one RunLoop::Delegate per thread. |
| 59 DCHECK(!tls_delegate.Get().Get()); | 73 DCHECK(!tls_delegate.Get().Get()); |
| 60 tls_delegate.Get().Set(delegate); | 74 tls_delegate.Get().Set(delegate); |
| 61 delegate->bound_ = true; | 75 delegate->bound_ = true; |
| 62 | 76 |
| 63 return &delegate->client_interface_; | 77 return &delegate->client_interface_; |
| 64 } | 78 } |
| 65 | 79 |
| 66 RunLoop::RunLoop() : delegate_(tls_delegate.Get().Get()), weak_factory_(this) { | 80 RunLoop::RunLoop() |
| 81 : delegate_(tls_delegate.Get().Get()), | |
| 82 origin_task_runner_(ThreadTaskRunnerHandle::Get()), | |
| 83 weak_factory_(this) { | |
| 67 // A RunLoop::Delegate must be bound to this thread prior to using RunLoop. | 84 // A RunLoop::Delegate must be bound to this thread prior to using RunLoop. |
| 68 DCHECK(delegate_); | 85 DCHECK(delegate_); |
| 86 DCHECK(origin_task_runner_); | |
| 69 } | 87 } |
| 70 | 88 |
| 71 RunLoop::~RunLoop() { | 89 RunLoop::~RunLoop() { |
| 72 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. | 90 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. |
| 73 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 91 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 74 } | 92 } |
| 75 | 93 |
| 76 void RunLoop::Run() { | 94 void RunLoop::Run() { |
| 77 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 95 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 78 | 96 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 101 } | 119 } |
| 102 | 120 |
| 103 void RunLoop::RunUntilIdle() { | 121 void RunLoop::RunUntilIdle() { |
| 104 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 122 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 105 | 123 |
| 106 quit_when_idle_received_ = true; | 124 quit_when_idle_received_ = true; |
| 107 Run(); | 125 Run(); |
| 108 } | 126 } |
| 109 | 127 |
| 110 void RunLoop::Quit() { | 128 void RunLoop::Quit() { |
| 111 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 129 // Thread-safe. |
| 130 | |
| 131 // This can only be hit if run_loop->Quit() is called directly (QuitClosure() | |
| 132 // proxies through ProxyToTaskRunner() as it can only deref its WeakPtr on | |
| 133 // |origin_task_runner_|). | |
| 134 if (!origin_task_runner_->RunsTasksInCurrentSequence()) { | |
| 135 origin_task_runner_->PostTask(FROM_HERE, | |
| 136 base::Bind(&RunLoop::Quit, Unretained(this))); | |
| 137 return; | |
| 138 } | |
| 112 | 139 |
| 113 quit_called_ = true; | 140 quit_called_ = true; |
| 114 if (running_ && delegate_->active_run_loops_.top() == this) { | 141 if (running_ && delegate_->active_run_loops_.top() == this) { |
| 115 // This is the inner-most RunLoop, so quit now. | 142 // This is the inner-most RunLoop, so quit now. |
| 116 delegate_->Quit(); | 143 delegate_->Quit(); |
| 117 } | 144 } |
| 118 } | 145 } |
| 119 | 146 |
| 120 void RunLoop::QuitWhenIdle() { | 147 void RunLoop::QuitWhenIdle() { |
| 121 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 148 // Thread-safe. |
| 149 | |
| 150 // This can only be hit if run_loop->QuitWhenIdle() is called directly | |
| 151 // (QuitWhenIdleClosure() proxies through ProxyToTaskRunner() as it can only | |
| 152 // deref its WeakPtr on |origin_task_runner_|). | |
| 153 if (!origin_task_runner_->RunsTasksInCurrentSequence()) { | |
| 154 origin_task_runner_->PostTask( | |
| 155 FROM_HERE, base::Bind(&RunLoop::QuitWhenIdle, Unretained(this))); | |
| 156 return; | |
| 157 } | |
| 158 | |
| 122 quit_when_idle_received_ = true; | 159 quit_when_idle_received_ = true; |
| 123 } | 160 } |
| 124 | 161 |
| 125 base::Closure RunLoop::QuitClosure() { | 162 base::Closure RunLoop::QuitClosure() { |
| 126 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. | 163 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. |
| 127 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 164 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 128 return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()); | 165 |
| 166 // Need to use ProxyToTaskRunner() as WeakPtrs vended from | |
| 167 // |weak_factory_| may only be accessed on |origin_task_runner_|. | |
| 168 // TODO(gab): It feels wrong that QuitClosure() is bound to a WeakPtr. | |
| 169 return base::Bind(&ProxyToTaskRunner, origin_task_runner_, | |
| 170 base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr())); | |
| 129 } | 171 } |
| 130 | 172 |
| 131 base::Closure RunLoop::QuitWhenIdleClosure() { | 173 base::Closure RunLoop::QuitWhenIdleClosure() { |
| 132 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. | 174 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. |
| 133 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 175 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 134 return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()); | 176 |
| 177 // Need to use ProxyToTaskRunner() as WeakPtrs vended from | |
| 178 // |weak_factory_| may only be accessed on |origin_task_runner_|. | |
| 179 // TODO(gab): It feels wrong that QuitWhenIdleClosure() is bound to a WeakPtr. | |
| 180 return base::Bind( | |
| 181 &ProxyToTaskRunner, origin_task_runner_, | |
| 182 base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr())); | |
| 135 } | 183 } |
| 136 | 184 |
| 137 // static | 185 // static |
| 138 bool RunLoop::IsRunningOnCurrentThread() { | 186 bool RunLoop::IsRunningOnCurrentThread() { |
| 139 Delegate* delegate = tls_delegate.Get().Get(); | 187 Delegate* delegate = tls_delegate.Get().Get(); |
| 140 return delegate && !delegate->active_run_loops_.empty(); | 188 return delegate && !delegate->active_run_loops_.empty(); |
| 141 } | 189 } |
| 142 | 190 |
| 143 // static | 191 // static |
| 144 bool RunLoop::IsNestedOnCurrentThread() { | 192 bool RunLoop::IsNestedOnCurrentThread() { |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 168 } | 216 } |
| 169 | 217 |
| 170 // static | 218 // static |
| 171 void RunLoop::DisallowNestingOnCurrentThread() { | 219 void RunLoop::DisallowNestingOnCurrentThread() { |
| 172 tls_delegate.Get().Get()->allow_nesting_ = false; | 220 tls_delegate.Get().Get()->allow_nesting_ = false; |
| 173 } | 221 } |
| 174 | 222 |
| 175 bool RunLoop::BeforeRun() { | 223 bool RunLoop::BeforeRun() { |
| 176 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 224 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 177 | 225 |
| 226 #if DCHECK_IS_ON() | |
| 178 DCHECK(!run_called_); | 227 DCHECK(!run_called_); |
| 179 run_called_ = true; | 228 run_called_ = true; |
| 229 #endif // DCHECK_IS_ON() | |
| 180 | 230 |
| 181 // Allow Quit to be called before Run. | 231 // Allow Quit to be called before Run. |
| 182 if (quit_called_) | 232 if (quit_called_) |
| 183 return false; | 233 return false; |
| 184 | 234 |
| 185 auto& active_run_loops_ = delegate_->active_run_loops_; | 235 auto& active_run_loops_ = delegate_->active_run_loops_; |
| 186 active_run_loops_.push(this); | 236 active_run_loops_.push(this); |
| 187 | 237 |
| 188 const bool is_nested = active_run_loops_.size() > 1; | 238 const bool is_nested = active_run_loops_.size() > 1; |
| 189 | 239 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 208 | 258 |
| 209 RunLoop* previous_run_loop = | 259 RunLoop* previous_run_loop = |
| 210 active_run_loops_.empty() ? nullptr : active_run_loops_.top(); | 260 active_run_loops_.empty() ? nullptr : active_run_loops_.top(); |
| 211 | 261 |
| 212 // Execute deferred QuitNow, if any: | 262 // Execute deferred QuitNow, if any: |
| 213 if (previous_run_loop && previous_run_loop->quit_called_) | 263 if (previous_run_loop && previous_run_loop->quit_called_) |
| 214 delegate_->Quit(); | 264 delegate_->Quit(); |
| 215 } | 265 } |
| 216 | 266 |
| 217 } // namespace base | 267 } // namespace base |
| OLD | NEW |