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

Side by Side Diff: base/run_loop.cc

Issue 2818533003: Make nesting/running states a RunLoop rather than a MessageLoop concept. (Closed)
Patch Set: still need to check MessageLoop::current() in Mojo's RunLoopNestingObserver::GetForThread() Created 3 years, 7 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
« no previous file with comments | « base/run_loop.h ('k') | base/run_loop_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // A vector-based stack is more memory efficient than the default deque-based
23 // stack as the active RunLoop stack isn't expected to ever have more than a
24 // few entries.
25 using RunLoopStack = std::stack<RunLoop*, std::vector<RunLoop*>>;
26
27 ThreadLocalRunLoopState()
28 : slot_(&ThreadLocalRunLoopState::OnTLSDestruction) {}
29
30 ~ThreadLocalRunLoopState() = delete;
31
32 RunLoopStack& GetActiveRunLoops() {
33 return GetOrCreateInternalState()->active_run_loops;
34 }
35
36 ObserverList<RunLoop::NestingObserver>& GetNestingObservers() {
37 InternalState* state = GetOrCreateInternalState();
38 CHECK(state->allow_nesting);
39 return state->nesting_observers;
40 }
41
42 bool IsNestingAllowed() { return GetOrCreateInternalState()->allow_nesting; }
43
44 void DisallowNesting() { GetOrCreateInternalState()->allow_nesting = false; }
45
46 void Reset() {
47 InternalState* state = static_cast<InternalState*>(slot_.Get());
48 if (state) {
49 slot_.Set(nullptr);
50 delete state;
51 }
52 }
53
54 private:
55 struct InternalState {
56 bool allow_nesting = true;
57 RunLoopStack active_run_loops;
58 ObserverList<RunLoop::NestingObserver> nesting_observers;
59 };
60
61 static void OnTLSDestruction(void* internal_state) {
62 delete static_cast<InternalState*>(internal_state);
63 }
64
65 InternalState* GetOrCreateInternalState() {
66 InternalState* state = static_cast<InternalState*>(slot_.Get());
67 if (!state) {
68 state = new InternalState;
69 slot_.Set(static_cast<void*>(state));
70 }
71 return state;
72 }
73
74 ThreadLocalStorage::Slot slot_;
75
76 DISALLOW_COPY_AND_ASSIGN(ThreadLocalRunLoopState);
77 };
78
79 LazyInstance<ThreadLocalRunLoopState>::Leaky tls_run_loop_state =
80 LAZY_INSTANCE_INITIALIZER;
81
82 } // namespace
83
13 RunLoop::RunLoop() 84 RunLoop::RunLoop()
14 : loop_(MessageLoop::current()), 85 : 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) { 86 weak_factory_(this) {
22 DCHECK(loop_); 87 DCHECK(loop_);
23 } 88 }
24 89
25 RunLoop::~RunLoop() { 90 RunLoop::~RunLoop() {
91 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
92 // DCHECK(thread_checker_.CalledOnValidThread());
26 } 93 }
27 94
28 void RunLoop::Run() { 95 void RunLoop::Run() {
29 DCHECK(thread_checker_.CalledOnValidThread()); 96 DCHECK(thread_checker_.CalledOnValidThread());
97
30 if (!BeforeRun()) 98 if (!BeforeRun())
31 return; 99 return;
32 100
33 // Use task stopwatch to exclude the loop run time from the current task, if 101 // Use task stopwatch to exclude the loop run time from the current task, if
34 // any. 102 // any.
35 tracked_objects::TaskStopwatch stopwatch; 103 tracked_objects::TaskStopwatch stopwatch;
36 stopwatch.Start(); 104 stopwatch.Start();
37 loop_->RunHandler(); 105 loop_->RunHandler();
38 stopwatch.Stop(); 106 stopwatch.Stop();
39 107
40 AfterRun(); 108 AfterRun();
41 } 109 }
42 110
43 void RunLoop::RunUntilIdle() { 111 void RunLoop::RunUntilIdle() {
112 DCHECK(thread_checker_.CalledOnValidThread());
113
44 quit_when_idle_received_ = true; 114 quit_when_idle_received_ = true;
45 Run(); 115 Run();
46 } 116 }
47 117
48 void RunLoop::Quit() { 118 void RunLoop::Quit() {
49 DCHECK(thread_checker_.CalledOnValidThread()); 119 DCHECK(thread_checker_.CalledOnValidThread());
120
50 quit_called_ = true; 121 quit_called_ = true;
51 if (running_ && loop_->run_loop_ == this) { 122 if (running_ && loop_->run_loop_ == this) {
52 // This is the inner-most RunLoop, so quit now. 123 // This is the inner-most RunLoop, so quit now.
53 loop_->QuitNow(); 124 loop_->QuitNow();
54 } 125 }
55 } 126 }
56 127
57 void RunLoop::QuitWhenIdle() { 128 void RunLoop::QuitWhenIdle() {
58 DCHECK(thread_checker_.CalledOnValidThread()); 129 DCHECK(thread_checker_.CalledOnValidThread());
59 quit_when_idle_received_ = true; 130 quit_when_idle_received_ = true;
60 } 131 }
61 132
62 base::Closure RunLoop::QuitClosure() { 133 base::Closure RunLoop::QuitClosure() {
134 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
135 // DCHECK(thread_checker_.CalledOnValidThread());
63 return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()); 136 return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
64 } 137 }
65 138
66 base::Closure RunLoop::QuitWhenIdleClosure() { 139 base::Closure RunLoop::QuitWhenIdleClosure() {
140 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
141 // DCHECK(thread_checker_.CalledOnValidThread());
67 return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()); 142 return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr());
68 } 143 }
69 144
145 // static
146 void RunLoop::ResetTLSState() {
147 tls_run_loop_state.Get().Reset();
148 }
149
150 // static
151 bool RunLoop::IsRunningOnCurrentThread() {
152 return !tls_run_loop_state.Get().GetActiveRunLoops().empty();
153 }
154
155 // static
156 bool RunLoop::IsNestedOnCurrentThread() {
157 return tls_run_loop_state.Get().GetActiveRunLoops().size() > 1;
158 }
159
160 // static
161 void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
162 tls_run_loop_state.Get().GetNestingObservers().AddObserver(observer);
163 }
164
165 // static
166 void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
167 tls_run_loop_state.Get().GetNestingObservers().RemoveObserver(observer);
168 }
169
170 // static
171 bool RunLoop::IsNestingAllowedOnCurrentThread() {
172 return tls_run_loop_state.Get().IsNestingAllowed();
173 }
174
175 // static
176 void RunLoop::DisallowNestingOnCurrentThread() {
177 tls_run_loop_state.Get().DisallowNesting();
178 }
179
70 bool RunLoop::BeforeRun() { 180 bool RunLoop::BeforeRun() {
181 DCHECK(thread_checker_.CalledOnValidThread());
182
71 DCHECK(!run_called_); 183 DCHECK(!run_called_);
72 run_called_ = true; 184 run_called_ = true;
73 185
74 // Allow Quit to be called before Run. 186 // Allow Quit to be called before Run.
75 if (quit_called_) 187 if (quit_called_)
76 return false; 188 return false;
77 189
78 // Push RunLoop stack: 190 auto& active_run_loops = tls_run_loop_state.Get().GetActiveRunLoops();
79 previous_run_loop_ = loop_->run_loop_; 191 active_run_loops.push(this);
80 run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1; 192
193 const bool is_nested = active_run_loops.size() > 1;
194
195 // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop
196 // further. http://crbug.com/703346
81 loop_->run_loop_ = this; 197 loop_->run_loop_ = this;
198 loop_->is_nested_ = is_nested;
82 199
83 if (run_depth_ > 1) 200 if (is_nested) {
84 loop_->NotifyBeginNestedLoop(); 201 CHECK(tls_run_loop_state.Get().IsNestingAllowed());
202 for (auto& observer : tls_run_loop_state.Get().GetNestingObservers())
203 observer.OnBeginNestedRunLoop();
204 }
85 205
86 running_ = true; 206 running_ = true;
87 return true; 207 return true;
88 } 208 }
89 209
90 void RunLoop::AfterRun() { 210 void RunLoop::AfterRun() {
211 DCHECK(thread_checker_.CalledOnValidThread());
212
91 running_ = false; 213 running_ = false;
92 214
93 // Pop RunLoop stack: 215 auto& active_run_loops = tls_run_loop_state.Get().GetActiveRunLoops();
94 loop_->run_loop_ = previous_run_loop_; 216 DCHECK_EQ(active_run_loops.top(), this);
217 active_run_loops.pop();
218
219 RunLoop* previous_run_loop =
220 active_run_loops.empty() ? nullptr : active_run_loops.top();
221 loop_->run_loop_ = previous_run_loop;
222 loop_->is_nested_ = active_run_loops.size() > 1;
95 223
96 // Execute deferred QuitNow, if any: 224 // Execute deferred QuitNow, if any:
97 if (previous_run_loop_ && previous_run_loop_->quit_called_) 225 if (previous_run_loop && previous_run_loop->quit_called_)
98 loop_->QuitNow(); 226 loop_->QuitNow();
99 } 227 }
100 228
101 } // namespace base 229 } // namespace base
OLDNEW
« no previous file with comments | « base/run_loop.h ('k') | base/run_loop_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698