blob: 072684f6c8436b02f3a7a1a4498f32bb4ae322d8 [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"
vadimt12f0f7d2014-09-15 19:19:3813#include "base/tracked_objects.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
gab273551962017-05-18 06:01:1036RunLoop::Delegate::Delegate() {
37 // 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 Charettee2b632b2017-08-02 03:52:1651bool RunLoop::Delegate::Client::ShouldQuitWhenIdle() const {
gab273551962017-05-18 06:01:1052 DCHECK_CALLED_ON_VALID_THREAD(outer_->bound_thread_checker_);
53 DCHECK(outer_->bound_);
Gabriel Charettee2b632b2017-08-02 03:52:1654 return outer_->active_run_loops_.top()->quit_when_idle_received_;
gab273551962017-05-18 06:01:1055}
56
57bool RunLoop::Delegate::Client::IsNested() const {
58 DCHECK_CALLED_ON_VALID_THREAD(outer_->bound_thread_checker_);
59 DCHECK(outer_->bound_);
60 return outer_->active_run_loops_.size() > 1;
61}
62
63RunLoop::Delegate::Client::Client(Delegate* outer) : outer_(outer) {}
64
Gabriel Charette0592c3a2017-07-26 12:02:0465// static
gab273551962017-05-18 06:01:1066RunLoop::Delegate::Client* RunLoop::RegisterDelegateForCurrentThread(
67 Delegate* delegate) {
68 // Bind |delegate| to this thread.
69 DCHECK(!delegate->bound_);
70 DCHECK_CALLED_ON_VALID_THREAD(delegate->bound_thread_checker_);
71
72 // There can only be one RunLoop::Delegate per thread.
73 DCHECK(!tls_delegate.Get().Get());
74 tls_delegate.Get().Set(delegate);
75 delegate->bound_ = true;
76
77 return &delegate->client_interface_;
78}
79
gabcf5e4ce2017-05-19 22:56:5780RunLoop::RunLoop()
81 : delegate_(tls_delegate.Get().Get()),
82 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_);
[email protected]8e937c1e2012-06-28 22:57:3087}
88
[email protected]8e937c1e2012-06-28 22:57:3089RunLoop::~RunLoop() {
gab7af9dc02017-05-05 13:38:5490 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
gab980a52712017-05-18 16:20:1691 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]8e937c1e2012-06-28 22:57:3092}
93
94void RunLoop::Run() {
gab980a52712017-05-18 16:20:1695 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:5496
[email protected]8e937c1e2012-06-28 22:57:3097 if (!BeforeRun())
98 return;
vadimt12f0f7d2014-09-15 19:19:3899
gab980a52712017-05-18 16:20:16100 // It is okay to access this RunLoop from another sequence while Run() is
101 // active as this RunLoop won't touch its state until after that returns (if
102 // the RunLoop's state is accessed while processing Run(), it will be re-bound
103 // to the accessing sequence for the remainder of that Run() -- accessing from
104 // multiple sequences is still disallowed).
105 DETACH_FROM_SEQUENCE(sequence_checker_);
106
vadimt12f0f7d2014-09-15 19:19:38107 // Use task stopwatch to exclude the loop run time from the current task, if
108 // any.
109 tracked_objects::TaskStopwatch stopwatch;
vadimt20175532014-10-28 20:14:20110 stopwatch.Start();
gab273551962017-05-18 06:01:10111 delegate_->Run();
vadimt12f0f7d2014-09-15 19:19:38112 stopwatch.Stop();
113
gab980a52712017-05-18 16:20:16114 // Rebind this RunLoop to the current thread after Run().
115 DETACH_FROM_SEQUENCE(sequence_checker_);
116 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
117
[email protected]8e937c1e2012-06-28 22:57:30118 AfterRun();
119}
120
121void RunLoop::RunUntilIdle() {
gab980a52712017-05-18 16:20:16122 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:54123
[email protected]8e937c1e2012-06-28 22:57:30124 quit_when_idle_received_ = true;
125 Run();
126}
127
128void RunLoop::Quit() {
gabcf5e4ce2017-05-19 22:56:57129 // 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()) {
tzik0c100dc2017-06-26 06:13:17135 origin_task_runner_->PostTask(
136 FROM_HERE, base::BindOnce(&RunLoop::Quit, Unretained(this)));
gabcf5e4ce2017-05-19 22:56:57137 return;
138 }
gab7af9dc02017-05-05 13:38:54139
[email protected]8e937c1e2012-06-28 22:57:30140 quit_called_ = true;
gab273551962017-05-18 06:01:10141 if (running_ && delegate_->active_run_loops_.top() == this) {
[email protected]8e937c1e2012-06-28 22:57:30142 // This is the inner-most RunLoop, so quit now.
gab273551962017-05-18 06:01:10143 delegate_->Quit();
[email protected]8e937c1e2012-06-28 22:57:30144 }
145}
146
fdoraya4f28ec2016-06-10 00:08:58147void RunLoop::QuitWhenIdle() {
gabcf5e4ce2017-05-19 22:56:57148 // 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(
tzik0c100dc2017-06-26 06:13:17155 FROM_HERE, base::BindOnce(&RunLoop::QuitWhenIdle, Unretained(this)));
gabcf5e4ce2017-05-19 22:56:57156 return;
157 }
158
fdoraya4f28ec2016-06-10 00:08:58159 quit_when_idle_received_ = true;
160}
161
[email protected]8e937c1e2012-06-28 22:57:30162base::Closure RunLoop::QuitClosure() {
gab7af9dc02017-05-05 13:38:54163 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
gab980a52712017-05-18 16:20:16164 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gabcf5e4ce2017-05-19 22:56:57165
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()));
[email protected]8e937c1e2012-06-28 22:57:30171}
172
fdoraya3658602016-06-10 18:23:15173base::Closure RunLoop::QuitWhenIdleClosure() {
gab7af9dc02017-05-05 13:38:54174 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
gab980a52712017-05-18 16:20:16175 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gabcf5e4ce2017-05-19 22:56:57176
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()));
fdoraya3658602016-06-10 18:23:15183}
184
gab7af9dc02017-05-05 13:38:54185// static
gab7af9dc02017-05-05 13:38:54186bool RunLoop::IsRunningOnCurrentThread() {
gab273551962017-05-18 06:01:10187 Delegate* delegate = tls_delegate.Get().Get();
188 return delegate && !delegate->active_run_loops_.empty();
gab7af9dc02017-05-05 13:38:54189}
190
191// static
192bool RunLoop::IsNestedOnCurrentThread() {
gab273551962017-05-18 06:01:10193 Delegate* delegate = tls_delegate.Get().Get();
194 return delegate && delegate->active_run_loops_.size() > 1;
gab7af9dc02017-05-05 13:38:54195}
196
197// static
198void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
gab273551962017-05-18 06:01:10199 Delegate* delegate = tls_delegate.Get().Get();
200 DCHECK(delegate);
201 CHECK(delegate->allow_nesting_);
202 delegate->nesting_observers_.AddObserver(observer);
gab7af9dc02017-05-05 13:38:54203}
204
205// static
206void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
gab273551962017-05-18 06:01:10207 Delegate* delegate = tls_delegate.Get().Get();
208 DCHECK(delegate);
209 CHECK(delegate->allow_nesting_);
210 delegate->nesting_observers_.RemoveObserver(observer);
gab7af9dc02017-05-05 13:38:54211}
212
213// static
214bool RunLoop::IsNestingAllowedOnCurrentThread() {
gab273551962017-05-18 06:01:10215 return tls_delegate.Get().Get()->allow_nesting_;
gab7af9dc02017-05-05 13:38:54216}
217
218// static
219void RunLoop::DisallowNestingOnCurrentThread() {
gab273551962017-05-18 06:01:10220 tls_delegate.Get().Get()->allow_nesting_ = false;
gab7af9dc02017-05-05 13:38:54221}
222
Gabriel Charette0592c3a2017-07-26 12:02:04223// static
224void RunLoop::QuitCurrentDeprecated() {
225 DCHECK(IsRunningOnCurrentThread());
226 tls_delegate.Get().Get()->active_run_loops_.top()->Quit();
227}
228
229// static
230void RunLoop::QuitCurrentWhenIdleDeprecated() {
231 DCHECK(IsRunningOnCurrentThread());
232 tls_delegate.Get().Get()->active_run_loops_.top()->QuitWhenIdle();
233}
234
[email protected]8e937c1e2012-06-28 22:57:30235bool RunLoop::BeforeRun() {
gab980a52712017-05-18 16:20:16236 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:54237
gabcf5e4ce2017-05-19 22:56:57238#if DCHECK_IS_ON()
[email protected]8e937c1e2012-06-28 22:57:30239 DCHECK(!run_called_);
240 run_called_ = true;
gabcf5e4ce2017-05-19 22:56:57241#endif // DCHECK_IS_ON()
[email protected]8e937c1e2012-06-28 22:57:30242
243 // Allow Quit to be called before Run.
244 if (quit_called_)
245 return false;
246
gab273551962017-05-18 06:01:10247 auto& active_run_loops_ = delegate_->active_run_loops_;
248 active_run_loops_.push(this);
[email protected]8e937c1e2012-06-28 22:57:30249
gab273551962017-05-18 06:01:10250 const bool is_nested = active_run_loops_.size() > 1;
gab7af9dc02017-05-05 13:38:54251
252 if (is_nested) {
gab273551962017-05-18 06:01:10253 CHECK(delegate_->allow_nesting_);
254 for (auto& observer : delegate_->nesting_observers_)
gab7af9dc02017-05-05 13:38:54255 observer.OnBeginNestedRunLoop();
256 }
jamescookaacdfd02016-04-28 00:50:03257
[email protected]8e937c1e2012-06-28 22:57:30258 running_ = true;
259 return true;
260}
261
262void RunLoop::AfterRun() {
gab980a52712017-05-18 16:20:16263 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gab7af9dc02017-05-05 13:38:54264
[email protected]8e937c1e2012-06-28 22:57:30265 running_ = false;
266
gab273551962017-05-18 06:01:10267 auto& active_run_loops_ = delegate_->active_run_loops_;
268 DCHECK_EQ(active_run_loops_.top(), this);
269 active_run_loops_.pop();
gab7af9dc02017-05-05 13:38:54270
271 RunLoop* previous_run_loop =
gab273551962017-05-18 06:01:10272 active_run_loops_.empty() ? nullptr : active_run_loops_.top();
[email protected]8e937c1e2012-06-28 22:57:30273
Gabriel Charettee2b632b2017-08-02 03:52:16274 // Execute deferred Quit, if any:
gab7af9dc02017-05-05 13:38:54275 if (previous_run_loop && previous_run_loop->quit_called_)
gab273551962017-05-18 06:01:10276 delegate_->Quit();
[email protected]8e937c1e2012-06-28 22:57:30277}
278
279} // namespace base