Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: base/run_loop.cc

Issue 2818533003: Make nesting/running states a RunLoop rather than a MessageLoop concept. (Closed)
Patch Set: fix compile Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <stack>
8
7 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/lazy_instance.h"
11 #include "base/observer_list.h"
12 #include "base/threading/thread_local_storage.h"
8 #include "base/tracked_objects.h" 13 #include "base/tracked_objects.h"
9 #include "build/build_config.h" 14 #include "build/build_config.h"
10 15
11 namespace base { 16 namespace base {
12 17
18 namespace {
19
20 class ThreadLocalRunLoopState {
21 public:
22 ThreadLocalRunLoopState()
23 : slot_(&ThreadLocalRunLoopState::OnTLSDestruction) {}
24
25 ~ThreadLocalRunLoopState() = delete;
26
27 std::stack<RunLoop*>& GetActiveRunLoops() {
28 return GetOrCreateInternalState()->active_run_loops;
29 }
30
31 ObserverList<RunLoop::NestingObserver>& GetNestingObservers() {
32 InternalState* state = GetOrCreateInternalState();
33 CHECK(state->allow_nesting);
34 return state->nesting_observers;
35 }
36
37 bool IsNestingAllowed() { return GetOrCreateInternalState()->allow_nesting; }
38
39 void DisallowNesting() { GetOrCreateInternalState()->allow_nesting = false; }
40
41 private:
42 struct InternalState {
43 bool allow_nesting = true;
44 std::stack<RunLoop*> active_run_loops;
danakj 2017/04/20 14:57:32 stacks are deques by default which are terrible fo
gab 2017/04/20 16:22:02 Good point, done.
45 ObserverList<RunLoop::NestingObserver> nesting_observers;
46 };
47
48 static void OnTLSDestruction(void* internal_state) {
49 delete static_cast<InternalState*>(internal_state);
50 }
51
52 InternalState* GetOrCreateInternalState() {
53 InternalState* state = static_cast<InternalState*>(slot_.Get());
54 if (!state) {
55 state = new InternalState;
56 slot_.Set(static_cast<void*>(state));
57 }
58 return state;
59 }
60
61 ThreadLocalStorage::Slot slot_;
62
63 DISALLOW_COPY_AND_ASSIGN(ThreadLocalRunLoopState);
64 };
65
66 LazyInstance<ThreadLocalRunLoopState>::Leaky tls_run_loop_state =
67 LAZY_INSTANCE_INITIALIZER;
68
69 } // namespace
70
13 RunLoop::RunLoop() 71 RunLoop::RunLoop()
14 : loop_(MessageLoop::current()), 72 : loop_(MessageLoop::current()),
15 previous_run_loop_(NULL),
16 run_depth_(0),
17 run_called_(false),
18 quit_called_(false),
19 running_(false),
20 quit_when_idle_received_(false),
21 weak_factory_(this) { 73 weak_factory_(this) {
22 DCHECK(loop_); 74 DCHECK(loop_);
23 } 75 }
24 76
25 RunLoop::~RunLoop() { 77 RunLoop::~RunLoop() {
78 DCHECK(thread_checker_.CalledOnValidThread());
26 } 79 }
27 80
28 void RunLoop::Run() { 81 void RunLoop::Run() {
29 DCHECK(thread_checker_.CalledOnValidThread()); 82 DCHECK(thread_checker_.CalledOnValidThread());
83
30 if (!BeforeRun()) 84 if (!BeforeRun())
31 return; 85 return;
32 86
33 // Use task stopwatch to exclude the loop run time from the current task, if 87 // Use task stopwatch to exclude the loop run time from the current task, if
34 // any. 88 // any.
35 tracked_objects::TaskStopwatch stopwatch; 89 tracked_objects::TaskStopwatch stopwatch;
36 stopwatch.Start(); 90 stopwatch.Start();
37 loop_->RunHandler(); 91 loop_->RunHandler();
38 stopwatch.Stop(); 92 stopwatch.Stop();
39 93
40 AfterRun(); 94 AfterRun();
41 } 95 }
42 96
43 void RunLoop::RunUntilIdle() { 97 void RunLoop::RunUntilIdle() {
98 DCHECK(thread_checker_.CalledOnValidThread());
99
44 quit_when_idle_received_ = true; 100 quit_when_idle_received_ = true;
45 Run(); 101 Run();
46 } 102 }
47 103
48 void RunLoop::Quit() { 104 void RunLoop::Quit() {
49 DCHECK(thread_checker_.CalledOnValidThread()); 105 DCHECK(thread_checker_.CalledOnValidThread());
106
50 quit_called_ = true; 107 quit_called_ = true;
51 if (running_ && loop_->run_loop_ == this) { 108 if (running_ && loop_->run_loop_ == this) {
52 // This is the inner-most RunLoop, so quit now. 109 // This is the inner-most RunLoop, so quit now.
53 loop_->QuitNow(); 110 loop_->QuitNow();
54 } 111 }
55 } 112 }
56 113
57 void RunLoop::QuitWhenIdle() { 114 void RunLoop::QuitWhenIdle() {
58 DCHECK(thread_checker_.CalledOnValidThread()); 115 DCHECK(thread_checker_.CalledOnValidThread());
59 quit_when_idle_received_ = true; 116 quit_when_idle_received_ = true;
60 } 117 }
61 118
62 base::Closure RunLoop::QuitClosure() { 119 base::Closure RunLoop::QuitClosure() {
120 DCHECK(thread_checker_.CalledOnValidThread());
63 return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()); 121 return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
64 } 122 }
65 123
66 base::Closure RunLoop::QuitWhenIdleClosure() { 124 base::Closure RunLoop::QuitWhenIdleClosure() {
125 DCHECK(thread_checker_.CalledOnValidThread());
67 return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()); 126 return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr());
68 } 127 }
69 128
129 // static
130 bool RunLoop::IsRunningOnCurrentThread() {
131 return !tls_run_loop_state.Get().GetActiveRunLoops().empty();
132 }
133
134 // static
135 bool RunLoop::IsNestedOnCurrentThread() {
136 return tls_run_loop_state.Get().GetActiveRunLoops().size() > 1;
137 }
138
139 // static
140 void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
141 tls_run_loop_state.Get().GetNestingObservers().AddObserver(observer);
142 }
143
144 // static
145 void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
146 tls_run_loop_state.Get().GetNestingObservers().RemoveObserver(observer);
147 }
148
149 // static
150 bool RunLoop::IsNestingAllowedOnCurrentThread() {
151 return tls_run_loop_state.Get().IsNestingAllowed();
152 }
153
154 // static
155 void RunLoop::DisallowNestingOnCurrentThread() {
156 tls_run_loop_state.Get().DisallowNesting();
157 }
158
70 bool RunLoop::BeforeRun() { 159 bool RunLoop::BeforeRun() {
160 DCHECK(thread_checker_.CalledOnValidThread());
161
71 DCHECK(!run_called_); 162 DCHECK(!run_called_);
72 run_called_ = true; 163 run_called_ = true;
73 164
74 // Allow Quit to be called before Run. 165 // Allow Quit to be called before Run.
75 if (quit_called_) 166 if (quit_called_)
76 return false; 167 return false;
77 168
78 // Push RunLoop stack: 169 std::stack<RunLoop*>& active_run_loops =
danakj 2017/04/20 14:57:32 nit: auto?
gab 2017/04/20 16:22:01 Done.
79 previous_run_loop_ = loop_->run_loop_; 170 tls_run_loop_state.Get().GetActiveRunLoops();
80 run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1; 171 active_run_loops.push(this);
172
173 const bool is_nested = active_run_loops.size() > 1;
174
175 // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop
176 // further. http://crbug.com/703346
81 loop_->run_loop_ = this; 177 loop_->run_loop_ = this;
178 loop_->is_nested_ = is_nested;
82 179
83 if (run_depth_ > 1) 180 if (is_nested) {
84 loop_->NotifyBeginNestedLoop(); 181 CHECK(tls_run_loop_state.Get().IsNestingAllowed());
182 for (auto& observer : tls_run_loop_state.Get().GetNestingObservers())
183 observer.OnBeginNestedMessageLoop();
184 }
85 185
86 running_ = true; 186 running_ = true;
87 return true; 187 return true;
88 } 188 }
89 189
90 void RunLoop::AfterRun() { 190 void RunLoop::AfterRun() {
191 DCHECK(thread_checker_.CalledOnValidThread());
192
91 running_ = false; 193 running_ = false;
92 194
93 // Pop RunLoop stack: 195 std::stack<RunLoop*>& active_run_loops =
94 loop_->run_loop_ = previous_run_loop_; 196 tls_run_loop_state.Get().GetActiveRunLoops();
197 DCHECK_EQ(active_run_loops.top(), this);
198 active_run_loops.pop();
199
200 RunLoop* underlying_run_loop =
danakj 2017/04/20 14:57:32 nit: i liked previous better than underlying as a
gab 2017/04/20 16:22:01 Done.
201 active_run_loops.empty() ? nullptr : active_run_loops.top();
202 loop_->run_loop_ = underlying_run_loop;
203 loop_->is_nested_ = active_run_loops.size() > 1;
95 204
96 // Execute deferred QuitNow, if any: 205 // Execute deferred QuitNow, if any:
97 if (previous_run_loop_ && previous_run_loop_->quit_called_) 206 if (underlying_run_loop && underlying_run_loop->quit_called_)
98 loop_->QuitNow(); 207 loop_->QuitNow();
99 } 208 }
100 209
101 } // namespace base 210 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698