blob: 61230c62fdcce1935d7c30323be86da6d5a86e9a [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"
gabcf5e4ce2017-05-19 22:56:5710#include "base/single_thread_task_runner.h"
gab273551962017-05-18 06:01:1011#include "base/threading/thread_local.h"
gabcf5e4ce2017-05-19 22:56:5712#include "base/threading/thread_task_runner_handle.h"
avi9b6f42932015-12-26 22:15:1413#include "build/build_config.h"
[email protected]8e937c1e2012-06-28 22:57:3014
15namespace base {
16
gab7af9dc02017-05-05 13:38:5417namespace {
18
gab273551962017-05-18 06:01:1019LazyInstance<ThreadLocalPointer<RunLoop::Delegate>>::Leaky tls_delegate =
gab7af9dc02017-05-05 13:38:5420 LAZY_INSTANCE_INITIALIZER;
21
gabcf5e4ce2017-05-19 22:56:5722// Runs |closure| immediately if this is called on |task_runner|, otherwise
23// forwards |closure| to it.
24void ProxyToTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner,
25 OnceClosure closure) {
26 if (task_runner->RunsTasksInCurrentSequence()) {
27 std::move(closure).Run();
28 return;
29 }
30 task_runner->PostTask(FROM_HERE, std::move(closure));
31}
32
gab7af9dc02017-05-05 13:38:5433} // namespace
34
gab273551962017-05-18 06:01:1035RunLoop::Delegate::Delegate() {
36 // The Delegate can be created on another thread. It is only bound in
37 // RegisterDelegateForCurrentThread().
38 DETACH_FROM_THREAD(bound_thread_checker_);
39}
40
41RunLoop::Delegate::~Delegate() {
42 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
43 // A RunLoop::Delegate may be destroyed before it is bound, if so it may still
44 // be on its creation thread (e.g. a Thread that fails to start) and
45 // shouldn't disrupt that thread's state.
46 if (bound_)
47 tls_delegate.Get().Set(nullptr);
48}
49
Gabriel Charettee2b632b2017-08-02 03:52:1650bool RunLoop::Delegate::Client::ShouldQuitWhenIdle() const {
gab273551962017-05-18 06:01:1051 DCHECK_CALLED_ON_VALID_THREAD(outer_->bound_thread_checker_);
52 DCHECK(outer_->bound_);
Gabriel Charettee2b632b2017-08-02 03:52:1653 return outer_->active_run_loops_.top()->quit_when_idle_received_;
gab273551962017-05-18 06:01:1054}
55
56bool RunLoop::Delegate::Client::IsNested() const {
57 DCHECK_CALLED_ON_VALID_THREAD(outer_->bound_thread_checker_);
58 DCHECK(outer_->bound_);
59 return outer_->active_run_loops_.size() > 1;
60}
61
62RunLoop::Delegate::Client::Client(Delegate* outer) : outer_(outer) {}
63
Gabriel Charette0592c3a2017-07-26 12:02:0464// static
gab273551962017-05-18 06:01:1065RunLoop::Delegate::Client* RunLoop::RegisterDelegateForCurrentThread(
66 Delegate* delegate) {
67 // Bind |delegate| to this thread.
68 DCHECK(!delegate->bound_);
69 DCHECK_CALLED_ON_VALID_THREAD(delegate->bound_thread_checker_);
70
71 // There can only be one RunLoop::Delegate per thread.
72 DCHECK(!tls_delegate.Get().Get());
73 tls_delegate.Get().Set(delegate);
74 delegate->bound_ = true;
75
76 return &delegate->client_interface_;
77}
78
Gabriel Charette3ff403e2017-08-07 04:22:4879RunLoop::RunLoop(Type type)
gabcf5e4ce2017-05-19 22:56:5780 : delegate_(tls_delegate.Get().Get()),
Gabriel Charette3ff403e2017-08-07 04:22:4881 type_(type),
gabcf5e4ce2017-05-19 22:56:5782 origin_task_runner_(ThreadTaskRunnerHandle::Get()),
83 weak_factory_(this) {
Gabriel Charettee2b632b2017-08-02 03:52:1684 DCHECK(delegate_) << "A RunLoop::Delegate must be bound to this thread prior "
85 "to using RunLoop.";
gabcf5e4ce2017-05-19 22:56:5786 DCHECK(origin_task_runner_);
Gabriel Charette3ff403e2017-08-07 04:22:4887
88 DCHECK(IsNestingAllowedOnCurrentThread() ||
89 type_ != Type::kNestableTasksAllowed);
[email protected]8e937c1e2012-06-28 22:57:3090}
91
[email protected]8e937c1e2012-06-28 22:57:3092RunLoop::~RunLoop() {
gab7af9dc02017-05-05 13:38:5493 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
gab980a52712017-05-18 16:20:1694 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]8e937c1e2012-06-28 22:57:3095}
96
97void RunLoop::Run() {
gab980a52712017-05-18 16:20:1698 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:5499
[email protected]8e937c1e2012-06-28 22:57:30100 if (!BeforeRun())
101 return;
vadimt12f0f7d2014-09-15 19:19:38102
gab980a52712017-05-18 16:20:16103 // It is okay to access this RunLoop from another sequence while Run() is
104 // active as this RunLoop won't touch its state until after that returns (if
105 // the RunLoop's state is accessed while processing Run(), it will be re-bound
106 // to the accessing sequence for the remainder of that Run() -- accessing from
107 // multiple sequences is still disallowed).
108 DETACH_FROM_SEQUENCE(sequence_checker_);
109
Gabriel Charetteb030a4a2017-10-26 01:04:40110 DCHECK_EQ(this, delegate_->active_run_loops_.top());
111 const bool application_tasks_allowed =
112 delegate_->active_run_loops_.size() == 1U ||
113 type_ == Type::kNestableTasksAllowed;
114 delegate_->Run(application_tasks_allowed);
vadimt12f0f7d2014-09-15 19:19:38115
gab980a52712017-05-18 16:20:16116 // Rebind this RunLoop to the current thread after Run().
117 DETACH_FROM_SEQUENCE(sequence_checker_);
118 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
119
[email protected]8e937c1e2012-06-28 22:57:30120 AfterRun();
121}
122
123void RunLoop::RunUntilIdle() {
gab980a52712017-05-18 16:20:16124 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:54125
[email protected]8e937c1e2012-06-28 22:57:30126 quit_when_idle_received_ = true;
127 Run();
128}
129
130void RunLoop::Quit() {
gabcf5e4ce2017-05-19 22:56:57131 // Thread-safe.
132
133 // This can only be hit if run_loop->Quit() is called directly (QuitClosure()
134 // proxies through ProxyToTaskRunner() as it can only deref its WeakPtr on
135 // |origin_task_runner_|).
136 if (!origin_task_runner_->RunsTasksInCurrentSequence()) {
tzik0c100dc2017-06-26 06:13:17137 origin_task_runner_->PostTask(
138 FROM_HERE, base::BindOnce(&RunLoop::Quit, Unretained(this)));
gabcf5e4ce2017-05-19 22:56:57139 return;
140 }
gab7af9dc02017-05-05 13:38:54141
[email protected]8e937c1e2012-06-28 22:57:30142 quit_called_ = true;
gab273551962017-05-18 06:01:10143 if (running_ && delegate_->active_run_loops_.top() == this) {
[email protected]8e937c1e2012-06-28 22:57:30144 // This is the inner-most RunLoop, so quit now.
gab273551962017-05-18 06:01:10145 delegate_->Quit();
[email protected]8e937c1e2012-06-28 22:57:30146 }
147}
148
fdoraya4f28ec2016-06-10 00:08:58149void RunLoop::QuitWhenIdle() {
gabcf5e4ce2017-05-19 22:56:57150 // Thread-safe.
151
152 // This can only be hit if run_loop->QuitWhenIdle() is called directly
153 // (QuitWhenIdleClosure() proxies through ProxyToTaskRunner() as it can only
154 // deref its WeakPtr on |origin_task_runner_|).
155 if (!origin_task_runner_->RunsTasksInCurrentSequence()) {
156 origin_task_runner_->PostTask(
tzik0c100dc2017-06-26 06:13:17157 FROM_HERE, base::BindOnce(&RunLoop::QuitWhenIdle, Unretained(this)));
gabcf5e4ce2017-05-19 22:56:57158 return;
159 }
160
fdoraya4f28ec2016-06-10 00:08:58161 quit_when_idle_received_ = true;
162}
163
[email protected]8e937c1e2012-06-28 22:57:30164base::Closure RunLoop::QuitClosure() {
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_);
gabcf5e4ce2017-05-19 22:56:57167
168 // Need to use ProxyToTaskRunner() as WeakPtrs vended from
169 // |weak_factory_| may only be accessed on |origin_task_runner_|.
170 // TODO(gab): It feels wrong that QuitClosure() is bound to a WeakPtr.
171 return base::Bind(&ProxyToTaskRunner, origin_task_runner_,
172 base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()));
[email protected]8e937c1e2012-06-28 22:57:30173}
174
fdoraya3658602016-06-10 18:23:15175base::Closure RunLoop::QuitWhenIdleClosure() {
gab7af9dc02017-05-05 13:38:54176 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
gab980a52712017-05-18 16:20:16177 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gabcf5e4ce2017-05-19 22:56:57178
179 // Need to use ProxyToTaskRunner() as WeakPtrs vended from
180 // |weak_factory_| may only be accessed on |origin_task_runner_|.
181 // TODO(gab): It feels wrong that QuitWhenIdleClosure() is bound to a WeakPtr.
182 return base::Bind(
183 &ProxyToTaskRunner, origin_task_runner_,
184 base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()));
fdoraya3658602016-06-10 18:23:15185}
186
gab7af9dc02017-05-05 13:38:54187// static
gab7af9dc02017-05-05 13:38:54188bool RunLoop::IsRunningOnCurrentThread() {
gab273551962017-05-18 06:01:10189 Delegate* delegate = tls_delegate.Get().Get();
190 return delegate && !delegate->active_run_loops_.empty();
gab7af9dc02017-05-05 13:38:54191}
192
193// static
194bool RunLoop::IsNestedOnCurrentThread() {
gab273551962017-05-18 06:01:10195 Delegate* delegate = tls_delegate.Get().Get();
196 return delegate && delegate->active_run_loops_.size() > 1;
gab7af9dc02017-05-05 13:38:54197}
198
199// static
200void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
gab273551962017-05-18 06:01:10201 Delegate* delegate = tls_delegate.Get().Get();
202 DCHECK(delegate);
203 CHECK(delegate->allow_nesting_);
204 delegate->nesting_observers_.AddObserver(observer);
gab7af9dc02017-05-05 13:38:54205}
206
207// static
208void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
gab273551962017-05-18 06:01:10209 Delegate* delegate = tls_delegate.Get().Get();
210 DCHECK(delegate);
211 CHECK(delegate->allow_nesting_);
212 delegate->nesting_observers_.RemoveObserver(observer);
gab7af9dc02017-05-05 13:38:54213}
214
215// static
216bool RunLoop::IsNestingAllowedOnCurrentThread() {
gab273551962017-05-18 06:01:10217 return tls_delegate.Get().Get()->allow_nesting_;
gab7af9dc02017-05-05 13:38:54218}
219
220// static
221void RunLoop::DisallowNestingOnCurrentThread() {
gab273551962017-05-18 06:01:10222 tls_delegate.Get().Get()->allow_nesting_ = false;
gab7af9dc02017-05-05 13:38:54223}
224
Gabriel Charette0592c3a2017-07-26 12:02:04225// static
226void RunLoop::QuitCurrentDeprecated() {
227 DCHECK(IsRunningOnCurrentThread());
228 tls_delegate.Get().Get()->active_run_loops_.top()->Quit();
229}
230
231// static
232void RunLoop::QuitCurrentWhenIdleDeprecated() {
233 DCHECK(IsRunningOnCurrentThread());
234 tls_delegate.Get().Get()->active_run_loops_.top()->QuitWhenIdle();
235}
236
Gabriel Charettea44975052017-08-21 23:14:04237#if DCHECK_IS_ON()
238RunLoop::ScopedDisallowRunningForTesting::ScopedDisallowRunningForTesting()
239 : current_delegate_(tls_delegate.Get().Get()),
240 previous_run_allowance_(
241 current_delegate_ ? current_delegate_->allow_running_for_testing_
242 : false) {
243 if (current_delegate_)
244 current_delegate_->allow_running_for_testing_ = false;
245}
246
247RunLoop::ScopedDisallowRunningForTesting::~ScopedDisallowRunningForTesting() {
248 DCHECK_EQ(current_delegate_, tls_delegate.Get().Get());
249 if (current_delegate_)
250 current_delegate_->allow_running_for_testing_ = previous_run_allowance_;
251}
252#else // DCHECK_IS_ON()
253// Defined out of line so that the compiler doesn't inline these and realize
254// the scope has no effect and then throws an "unused variable" warning in
255// non-dcheck builds.
256RunLoop::ScopedDisallowRunningForTesting::ScopedDisallowRunningForTesting() =
257 default;
258RunLoop::ScopedDisallowRunningForTesting::~ScopedDisallowRunningForTesting() =
259 default;
260#endif // DCHECK_IS_ON()
261
[email protected]8e937c1e2012-06-28 22:57:30262bool RunLoop::BeforeRun() {
gab980a52712017-05-18 16:20:16263 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:54264
gabcf5e4ce2017-05-19 22:56:57265#if DCHECK_IS_ON()
Gabriel Charettea44975052017-08-21 23:14:04266 DCHECK(delegate_->allow_running_for_testing_)
267 << "RunLoop::Run() isn't allowed in the scope of a "
268 "ScopedDisallowRunningForTesting. Hint: if mixing "
269 "TestMockTimeTaskRunners on same thread, use TestMockTimeTaskRunner's "
270 "API instead of RunLoop to drive individual task runners.";
[email protected]8e937c1e2012-06-28 22:57:30271 DCHECK(!run_called_);
272 run_called_ = true;
gabcf5e4ce2017-05-19 22:56:57273#endif // DCHECK_IS_ON()
[email protected]8e937c1e2012-06-28 22:57:30274
275 // Allow Quit to be called before Run.
276 if (quit_called_)
277 return false;
278
gab273551962017-05-18 06:01:10279 auto& active_run_loops_ = delegate_->active_run_loops_;
280 active_run_loops_.push(this);
[email protected]8e937c1e2012-06-28 22:57:30281
gab273551962017-05-18 06:01:10282 const bool is_nested = active_run_loops_.size() > 1;
gab7af9dc02017-05-05 13:38:54283
284 if (is_nested) {
gab273551962017-05-18 06:01:10285 CHECK(delegate_->allow_nesting_);
286 for (auto& observer : delegate_->nesting_observers_)
gab7af9dc02017-05-05 13:38:54287 observer.OnBeginNestedRunLoop();
Gabriel Charette3ff403e2017-08-07 04:22:48288 if (type_ == Type::kNestableTasksAllowed)
289 delegate_->EnsureWorkScheduled();
gab7af9dc02017-05-05 13:38:54290 }
jamescookaacdfd02016-04-28 00:50:03291
[email protected]8e937c1e2012-06-28 22:57:30292 running_ = true;
293 return true;
294}
295
296void RunLoop::AfterRun() {
gab980a52712017-05-18 16:20:16297 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:54298
[email protected]8e937c1e2012-06-28 22:57:30299 running_ = false;
300
gab273551962017-05-18 06:01:10301 auto& active_run_loops_ = delegate_->active_run_loops_;
302 DCHECK_EQ(active_run_loops_.top(), this);
303 active_run_loops_.pop();
gab7af9dc02017-05-05 13:38:54304
305 RunLoop* previous_run_loop =
gab273551962017-05-18 06:01:10306 active_run_loops_.empty() ? nullptr : active_run_loops_.top();
[email protected]8e937c1e2012-06-28 22:57:30307
Gabriel Charettee2b632b2017-08-02 03:52:16308 // Execute deferred Quit, if any:
gab7af9dc02017-05-05 13:38:54309 if (previous_run_loop && previous_run_loop->quit_called_)
gab273551962017-05-18 06:01:10310 delegate_->Quit();
[email protected]8e937c1e2012-06-28 22:57:30311}
312
313} // namespace base