blob: d4d87d72a0ab709c2306aecdb2c769c7678d5b07 [file] [log] [blame]
[email protected]8e937c1e2012-06-28 22:57:301// 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
3// found in the LICENSE file.
4
5#include "base/run_loop.h"
6
7#include "base/bind.h"
gabcf5e4ce2017-05-19 22:56:578#include "base/callback.h"
gab7af9dc02017-05-05 13:38:549#include "base/lazy_instance.h"
Alexander Timin4f9c35c2018-11-01 20:15:2010#include "base/message_loop/message_loop.h"
gabcf5e4ce2017-05-19 22:56:5711#include "base/single_thread_task_runner.h"
gab273551962017-05-18 06:01:1012#include "base/threading/thread_local.h"
gabcf5e4ce2017-05-19 22:56:5713#include "base/threading/thread_task_runner_handle.h"
avi9b6f42932015-12-26 22:15:1414#include "build/build_config.h"
[email protected]8e937c1e2012-06-28 22:57:3015
16namespace base {
17
gab7af9dc02017-05-05 13:38:5418namespace {
19
gab273551962017-05-18 06:01:1020LazyInstance<ThreadLocalPointer<RunLoop::Delegate>>::Leaky tls_delegate =
gab7af9dc02017-05-05 13:38:5421 LAZY_INSTANCE_INITIALIZER;
22
gabcf5e4ce2017-05-19 22:56:5723// Runs |closure| immediately if this is called on |task_runner|, otherwise
24// forwards |closure| to it.
25void 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
gab7af9dc02017-05-05 13:38:5434} // namespace
35
Gabriel Charette50518fc2018-05-22 17:53:2236RunLoop::Delegate::Delegate() {
gab273551962017-05-18 06:01:1037 // The Delegate can be created on another thread. It is only bound in
38 // RegisterDelegateForCurrentThread().
39 DETACH_FROM_THREAD(bound_thread_checker_);
40}
41
42RunLoop::Delegate::~Delegate() {
43 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
44 // A RunLoop::Delegate may be destroyed before it is bound, if so it may still
45 // be on its creation thread (e.g. a Thread that fails to start) and
46 // shouldn't disrupt that thread's state.
47 if (bound_)
48 tls_delegate.Get().Set(nullptr);
49}
50
Gabriel Charettea3ec9612017-12-14 17:22:4051bool RunLoop::Delegate::ShouldQuitWhenIdle() {
Gabriel Charette50518fc2018-05-22 17:53:2252 return active_run_loops_.top()->quit_when_idle_received_;
gab273551962017-05-18 06:01:1053}
54
Gabriel Charette0592c3a2017-07-26 12:02:0455// static
Gabriel Charettea3ec9612017-12-14 17:22:4056void RunLoop::RegisterDelegateForCurrentThread(Delegate* delegate) {
gab273551962017-05-18 06:01:1057 // Bind |delegate| to this thread.
58 DCHECK(!delegate->bound_);
59 DCHECK_CALLED_ON_VALID_THREAD(delegate->bound_thread_checker_);
60
61 // There can only be one RunLoop::Delegate per thread.
Gabriel Charettefa5e7f0d2018-01-29 12:08:2162 DCHECK(!tls_delegate.Get().Get())
63 << "Error: Multiple RunLoop::Delegates registered on the same thread.\n\n"
64 "Hint: You perhaps instantiated a second "
65 "MessageLoop/ScopedTaskEnvironment on a thread that already had one?";
gab273551962017-05-18 06:01:1066 tls_delegate.Get().Set(delegate);
67 delegate->bound_ = true;
gab273551962017-05-18 06:01:1068}
69
Gabriel Charette3ff403e2017-08-07 04:22:4870RunLoop::RunLoop(Type type)
gabcf5e4ce2017-05-19 22:56:5771 : delegate_(tls_delegate.Get().Get()),
Gabriel Charette3ff403e2017-08-07 04:22:4872 type_(type),
gabcf5e4ce2017-05-19 22:56:5773 origin_task_runner_(ThreadTaskRunnerHandle::Get()),
74 weak_factory_(this) {
Gabriel Charettee2b632b2017-08-02 03:52:1675 DCHECK(delegate_) << "A RunLoop::Delegate must be bound to this thread prior "
76 "to using RunLoop.";
gabcf5e4ce2017-05-19 22:56:5777 DCHECK(origin_task_runner_);
[email protected]8e937c1e2012-06-28 22:57:3078}
79
[email protected]8e937c1e2012-06-28 22:57:3080RunLoop::~RunLoop() {
gab7af9dc02017-05-05 13:38:5481 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
gab980a52712017-05-18 16:20:1682 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]8e937c1e2012-06-28 22:57:3083}
84
85void RunLoop::Run() {
gab980a52712017-05-18 16:20:1686 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:5487
[email protected]8e937c1e2012-06-28 22:57:3088 if (!BeforeRun())
89 return;
vadimt12f0f7d2014-09-15 19:19:3890
gab980a52712017-05-18 16:20:1691 // It is okay to access this RunLoop from another sequence while Run() is
92 // active as this RunLoop won't touch its state until after that returns (if
93 // the RunLoop's state is accessed while processing Run(), it will be re-bound
94 // to the accessing sequence for the remainder of that Run() -- accessing from
95 // multiple sequences is still disallowed).
96 DETACH_FROM_SEQUENCE(sequence_checker_);
97
Gabriel Charetteb030a4a2017-10-26 01:04:4098 DCHECK_EQ(this, delegate_->active_run_loops_.top());
99 const bool application_tasks_allowed =
100 delegate_->active_run_loops_.size() == 1U ||
101 type_ == Type::kNestableTasksAllowed;
102 delegate_->Run(application_tasks_allowed);
vadimt12f0f7d2014-09-15 19:19:38103
gab980a52712017-05-18 16:20:16104 // Rebind this RunLoop to the current thread after Run().
105 DETACH_FROM_SEQUENCE(sequence_checker_);
106 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
107
[email protected]8e937c1e2012-06-28 22:57:30108 AfterRun();
109}
110
111void RunLoop::RunUntilIdle() {
gab980a52712017-05-18 16:20:16112 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:54113
[email protected]8e937c1e2012-06-28 22:57:30114 quit_when_idle_received_ = true;
115 Run();
116}
117
118void RunLoop::Quit() {
gabcf5e4ce2017-05-19 22:56:57119 // Thread-safe.
120
121 // This can only be hit if run_loop->Quit() is called directly (QuitClosure()
122 // proxies through ProxyToTaskRunner() as it can only deref its WeakPtr on
123 // |origin_task_runner_|).
124 if (!origin_task_runner_->RunsTasksInCurrentSequence()) {
tzik0c100dc2017-06-26 06:13:17125 origin_task_runner_->PostTask(
126 FROM_HERE, base::BindOnce(&RunLoop::Quit, Unretained(this)));
gabcf5e4ce2017-05-19 22:56:57127 return;
128 }
gab7af9dc02017-05-05 13:38:54129
[email protected]8e937c1e2012-06-28 22:57:30130 quit_called_ = true;
gab273551962017-05-18 06:01:10131 if (running_ && delegate_->active_run_loops_.top() == this) {
[email protected]8e937c1e2012-06-28 22:57:30132 // This is the inner-most RunLoop, so quit now.
gab273551962017-05-18 06:01:10133 delegate_->Quit();
[email protected]8e937c1e2012-06-28 22:57:30134 }
135}
136
fdoraya4f28ec2016-06-10 00:08:58137void RunLoop::QuitWhenIdle() {
gabcf5e4ce2017-05-19 22:56:57138 // Thread-safe.
139
140 // This can only be hit if run_loop->QuitWhenIdle() is called directly
141 // (QuitWhenIdleClosure() proxies through ProxyToTaskRunner() as it can only
142 // deref its WeakPtr on |origin_task_runner_|).
143 if (!origin_task_runner_->RunsTasksInCurrentSequence()) {
144 origin_task_runner_->PostTask(
tzik0c100dc2017-06-26 06:13:17145 FROM_HERE, base::BindOnce(&RunLoop::QuitWhenIdle, Unretained(this)));
gabcf5e4ce2017-05-19 22:56:57146 return;
147 }
148
fdoraya4f28ec2016-06-10 00:08:58149 quit_when_idle_received_ = true;
150}
151
[email protected]8e937c1e2012-06-28 22:57:30152base::Closure RunLoop::QuitClosure() {
gab7af9dc02017-05-05 13:38:54153 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
gab980a52712017-05-18 16:20:16154 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Wez325eafc2018-07-17 17:01:49155 allow_quit_current_deprecated_ = false;
gabcf5e4ce2017-05-19 22:56:57156
157 // Need to use ProxyToTaskRunner() as WeakPtrs vended from
158 // |weak_factory_| may only be accessed on |origin_task_runner_|.
159 // TODO(gab): It feels wrong that QuitClosure() is bound to a WeakPtr.
160 return base::Bind(&ProxyToTaskRunner, origin_task_runner_,
161 base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()));
[email protected]8e937c1e2012-06-28 22:57:30162}
163
fdoraya3658602016-06-10 18:23:15164base::Closure RunLoop::QuitWhenIdleClosure() {
gab7af9dc02017-05-05 13:38:54165 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
gab980a52712017-05-18 16:20:16166 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Wez325eafc2018-07-17 17:01:49167 allow_quit_current_deprecated_ = false;
gabcf5e4ce2017-05-19 22:56:57168
169 // Need to use ProxyToTaskRunner() as WeakPtrs vended from
170 // |weak_factory_| may only be accessed on |origin_task_runner_|.
171 // TODO(gab): It feels wrong that QuitWhenIdleClosure() is bound to a WeakPtr.
172 return base::Bind(
173 &ProxyToTaskRunner, origin_task_runner_,
174 base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()));
fdoraya3658602016-06-10 18:23:15175}
176
gab7af9dc02017-05-05 13:38:54177// static
gab7af9dc02017-05-05 13:38:54178bool RunLoop::IsRunningOnCurrentThread() {
gab273551962017-05-18 06:01:10179 Delegate* delegate = tls_delegate.Get().Get();
180 return delegate && !delegate->active_run_loops_.empty();
gab7af9dc02017-05-05 13:38:54181}
182
183// static
184bool RunLoop::IsNestedOnCurrentThread() {
gab273551962017-05-18 06:01:10185 Delegate* delegate = tls_delegate.Get().Get();
186 return delegate && delegate->active_run_loops_.size() > 1;
gab7af9dc02017-05-05 13:38:54187}
188
189// static
190void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
gab273551962017-05-18 06:01:10191 Delegate* delegate = tls_delegate.Get().Get();
192 DCHECK(delegate);
gab273551962017-05-18 06:01:10193 delegate->nesting_observers_.AddObserver(observer);
gab7af9dc02017-05-05 13:38:54194}
195
196// static
197void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
gab273551962017-05-18 06:01:10198 Delegate* delegate = tls_delegate.Get().Get();
199 DCHECK(delegate);
gab273551962017-05-18 06:01:10200 delegate->nesting_observers_.RemoveObserver(observer);
gab7af9dc02017-05-05 13:38:54201}
202
203// static
Gabriel Charette0592c3a2017-07-26 12:02:04204void RunLoop::QuitCurrentDeprecated() {
205 DCHECK(IsRunningOnCurrentThread());
Wez325eafc2018-07-17 17:01:49206 Delegate* delegate = tls_delegate.Get().Get();
207 DCHECK(delegate->active_run_loops_.top()->allow_quit_current_deprecated_)
208 << "Please migrate off QuitCurrentDeprecated(), e.g. to QuitClosure().";
209 delegate->active_run_loops_.top()->Quit();
Gabriel Charette0592c3a2017-07-26 12:02:04210}
211
212// static
213void RunLoop::QuitCurrentWhenIdleDeprecated() {
214 DCHECK(IsRunningOnCurrentThread());
Wez325eafc2018-07-17 17:01:49215 Delegate* delegate = tls_delegate.Get().Get();
216 DCHECK(delegate->active_run_loops_.top()->allow_quit_current_deprecated_)
217 << "Please migrate off QuitCurrentWhenIdleDeprecated(), e.g. to "
218 "QuitWhenIdleClosure().";
219 delegate->active_run_loops_.top()->QuitWhenIdle();
Gabriel Charette0592c3a2017-07-26 12:02:04220}
221
Gabriel Charette5bc88412018-05-16 03:28:25222// static
223Closure RunLoop::QuitCurrentWhenIdleClosureDeprecated() {
Wez325eafc2018-07-17 17:01:49224 // TODO(844016): Fix callsites and enable this check, or remove the API.
225 // Delegate* delegate = tls_delegate.Get().Get();
226 // DCHECK(delegate->active_run_loops_.top()->allow_quit_current_deprecated_)
227 // << "Please migrate off QuitCurrentWhenIdleClosureDeprecated(), e.g to "
228 // "QuitWhenIdleClosure().";
Gabriel Charette5bc88412018-05-16 03:28:25229 return Bind(&RunLoop::QuitCurrentWhenIdleDeprecated);
230}
231
Gabriel Charettea44975052017-08-21 23:14:04232#if DCHECK_IS_ON()
233RunLoop::ScopedDisallowRunningForTesting::ScopedDisallowRunningForTesting()
234 : current_delegate_(tls_delegate.Get().Get()),
235 previous_run_allowance_(
236 current_delegate_ ? current_delegate_->allow_running_for_testing_
237 : false) {
238 if (current_delegate_)
239 current_delegate_->allow_running_for_testing_ = false;
240}
241
242RunLoop::ScopedDisallowRunningForTesting::~ScopedDisallowRunningForTesting() {
243 DCHECK_EQ(current_delegate_, tls_delegate.Get().Get());
244 if (current_delegate_)
245 current_delegate_->allow_running_for_testing_ = previous_run_allowance_;
246}
247#else // DCHECK_IS_ON()
248// Defined out of line so that the compiler doesn't inline these and realize
249// the scope has no effect and then throws an "unused variable" warning in
250// non-dcheck builds.
251RunLoop::ScopedDisallowRunningForTesting::ScopedDisallowRunningForTesting() =
252 default;
253RunLoop::ScopedDisallowRunningForTesting::~ScopedDisallowRunningForTesting() =
254 default;
255#endif // DCHECK_IS_ON()
256
[email protected]8e937c1e2012-06-28 22:57:30257bool RunLoop::BeforeRun() {
gab980a52712017-05-18 16:20:16258 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:54259
gabcf5e4ce2017-05-19 22:56:57260#if DCHECK_IS_ON()
Gabriel Charettea44975052017-08-21 23:14:04261 DCHECK(delegate_->allow_running_for_testing_)
262 << "RunLoop::Run() isn't allowed in the scope of a "
263 "ScopedDisallowRunningForTesting. Hint: if mixing "
264 "TestMockTimeTaskRunners on same thread, use TestMockTimeTaskRunner's "
265 "API instead of RunLoop to drive individual task runners.";
[email protected]8e937c1e2012-06-28 22:57:30266 DCHECK(!run_called_);
267 run_called_ = true;
gabcf5e4ce2017-05-19 22:56:57268#endif // DCHECK_IS_ON()
[email protected]8e937c1e2012-06-28 22:57:30269
270 // Allow Quit to be called before Run.
271 if (quit_called_)
272 return false;
273
gab273551962017-05-18 06:01:10274 auto& active_run_loops_ = delegate_->active_run_loops_;
275 active_run_loops_.push(this);
[email protected]8e937c1e2012-06-28 22:57:30276
gab273551962017-05-18 06:01:10277 const bool is_nested = active_run_loops_.size() > 1;
gab7af9dc02017-05-05 13:38:54278
279 if (is_nested) {
gab273551962017-05-18 06:01:10280 for (auto& observer : delegate_->nesting_observers_)
gab7af9dc02017-05-05 13:38:54281 observer.OnBeginNestedRunLoop();
Gabriel Charette3ff403e2017-08-07 04:22:48282 if (type_ == Type::kNestableTasksAllowed)
283 delegate_->EnsureWorkScheduled();
gab7af9dc02017-05-05 13:38:54284 }
jamescookaacdfd02016-04-28 00:50:03285
[email protected]8e937c1e2012-06-28 22:57:30286 running_ = true;
287 return true;
288}
289
290void RunLoop::AfterRun() {
gab980a52712017-05-18 16:20:16291 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:54292
[email protected]8e937c1e2012-06-28 22:57:30293 running_ = false;
294
gab273551962017-05-18 06:01:10295 auto& active_run_loops_ = delegate_->active_run_loops_;
296 DCHECK_EQ(active_run_loops_.top(), this);
297 active_run_loops_.pop();
gab7af9dc02017-05-05 13:38:54298
299 RunLoop* previous_run_loop =
gab273551962017-05-18 06:01:10300 active_run_loops_.empty() ? nullptr : active_run_loops_.top();
[email protected]8e937c1e2012-06-28 22:57:30301
Francois Doray80bdddf2018-01-04 16:17:32302 if (previous_run_loop) {
303 for (auto& observer : delegate_->nesting_observers_)
304 observer.OnExitNestedRunLoop();
305 }
306
Gabriel Charettee2b632b2017-08-02 03:52:16307 // Execute deferred Quit, if any:
gab7af9dc02017-05-05 13:38:54308 if (previous_run_loop && previous_run_loop->quit_called_)
gab273551962017-05-18 06:01:10309 delegate_->Quit();
[email protected]8e937c1e2012-06-28 22:57:30310}
311
312} // namespace base