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()) { |
| 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 |