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

Side by Side Diff: base/run_loop.cc

Issue 2880453003: Introduce RunLoop::Delegate splitting RunLoop/MessageLoop some more. (Closed)
Patch Set: 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
« base/run_loop.h ('K') | « base/run_loop.h ('k') | no next file » | 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
9 #include "base/bind.h" 7 #include "base/bind.h"
10 #include "base/lazy_instance.h" 8 #include "base/lazy_instance.h"
11 #include "base/observer_list.h" 9 #include "base/threading/thread_local.h"
12 #include "base/threading/thread_local_storage.h"
13 #include "base/tracked_objects.h" 10 #include "base/tracked_objects.h"
14 #include "build/build_config.h" 11 #include "build/build_config.h"
15 12
16 namespace base { 13 namespace base {
17 14
18 namespace { 15 namespace {
19 16
20 class ThreadLocalRunLoopState { 17 LazyInstance<ThreadLocalPointer<RunLoop::Delegate>>::Leaky tls_delegate =
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; 18 LAZY_INSTANCE_INITIALIZER;
81 19
82 } // namespace 20 } // namespace
83 21
84 RunLoop::RunLoop() 22 RunLoop::Delegate::Delegate() {
85 : loop_(MessageLoop::current()), 23 // The Delegate can be created on another thread. It is only bound in
86 weak_factory_(this) { 24 // BindToCurrentThread().
87 DCHECK(loop_); 25 DETACH_FROM_THREAD(bound_thread_checker_);
26 }
27
28 RunLoop::Delegate::~Delegate() {
29 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
30 // A RunLoop::Delegate may be destroyed before it is bound, if so it may still
31 // be on its creation thread (e.g. a Thread that fails to start) and
32 // shouldn't disrupt that thread's state.
33 if (bound_)
34 tls_delegate.Get().Set(nullptr);
35 }
36
37 bool RunLoop::Delegate::IsNested() const {
38 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
39 DCHECK(bound_);
40 return active_run_loops_.size() > 1;
41 }
42
43 RunLoop* RunLoop::Delegate::GetTopMostRunLoop() const {
44 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
45 DCHECK(bound_);
46 return active_run_loops_.empty() ? nullptr : active_run_loops_.top();
47 }
48
49 void RunLoop::Delegate::BindToCurrentThread() {
50 // Bind the checker to this thread.
51 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
52
53 // There can only be one RunLoop::Delegate per thread.
54 DCHECK(!tls_delegate.Get().Get());
55 DCHECK(!bound_);
56 tls_delegate.Get().Set(this);
57 bound_ = true;
58 }
59
60 RunLoop::RunLoop() : delegate_(tls_delegate.Get().Get()), weak_factory_(this) {
61 // A RunLoop::Delegate must be bound to this thread prior to using RunLoop.
62 DCHECK(delegate_);
88 } 63 }
89 64
90 RunLoop::~RunLoop() { 65 RunLoop::~RunLoop() {
91 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. 66 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
92 // DCHECK(thread_checker_.CalledOnValidThread()); 67 // DCHECK(thread_checker_.CalledOnValidThread());
93 } 68 }
94 69
95 void RunLoop::Run() { 70 void RunLoop::Run() {
96 DCHECK(thread_checker_.CalledOnValidThread()); 71 DCHECK(thread_checker_.CalledOnValidThread());
97 72
98 if (!BeforeRun()) 73 if (!BeforeRun())
99 return; 74 return;
100 75
101 // Use task stopwatch to exclude the loop run time from the current task, if 76 // Use task stopwatch to exclude the loop run time from the current task, if
102 // any. 77 // any.
103 tracked_objects::TaskStopwatch stopwatch; 78 tracked_objects::TaskStopwatch stopwatch;
104 stopwatch.Start(); 79 stopwatch.Start();
105 loop_->RunHandler(); 80 delegate_->Run();
106 stopwatch.Stop(); 81 stopwatch.Stop();
107 82
108 AfterRun(); 83 AfterRun();
109 } 84 }
110 85
111 void RunLoop::RunUntilIdle() { 86 void RunLoop::RunUntilIdle() {
112 DCHECK(thread_checker_.CalledOnValidThread()); 87 DCHECK(thread_checker_.CalledOnValidThread());
113 88
114 quit_when_idle_received_ = true; 89 quit_when_idle_received_ = true;
115 Run(); 90 Run();
116 } 91 }
117 92
118 void RunLoop::Quit() { 93 void RunLoop::Quit() {
119 DCHECK(thread_checker_.CalledOnValidThread()); 94 DCHECK(thread_checker_.CalledOnValidThread());
120 95
121 quit_called_ = true; 96 quit_called_ = true;
122 if (running_ && loop_->run_loop_ == this) { 97 if (running_ && delegate_->active_run_loops_.top() == this) {
123 // This is the inner-most RunLoop, so quit now. 98 // This is the inner-most RunLoop, so quit now.
124 loop_->QuitNow(); 99 delegate_->Quit();
125 } 100 }
126 } 101 }
127 102
128 void RunLoop::QuitWhenIdle() { 103 void RunLoop::QuitWhenIdle() {
129 DCHECK(thread_checker_.CalledOnValidThread()); 104 DCHECK(thread_checker_.CalledOnValidThread());
130 quit_when_idle_received_ = true; 105 quit_when_idle_received_ = true;
131 } 106 }
132 107
133 base::Closure RunLoop::QuitClosure() { 108 base::Closure RunLoop::QuitClosure() {
134 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. 109 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
135 // DCHECK(thread_checker_.CalledOnValidThread()); 110 // DCHECK(thread_checker_.CalledOnValidThread());
136 return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()); 111 return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
137 } 112 }
138 113
139 base::Closure RunLoop::QuitWhenIdleClosure() { 114 base::Closure RunLoop::QuitWhenIdleClosure() {
140 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. 115 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
141 // DCHECK(thread_checker_.CalledOnValidThread()); 116 // DCHECK(thread_checker_.CalledOnValidThread());
142 return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()); 117 return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr());
143 } 118 }
144 119
145 // static 120 // static
146 void RunLoop::ResetTLSState() {
147 tls_run_loop_state.Get().Reset();
148 }
149
150 // static
151 bool RunLoop::IsRunningOnCurrentThread() { 121 bool RunLoop::IsRunningOnCurrentThread() {
152 return !tls_run_loop_state.Get().GetActiveRunLoops().empty(); 122 return !tls_delegate.Get().Get()->active_run_loops_.empty();
153 } 123 }
154 124
155 // static 125 // static
156 bool RunLoop::IsNestedOnCurrentThread() { 126 bool RunLoop::IsNestedOnCurrentThread() {
157 return tls_run_loop_state.Get().GetActiveRunLoops().size() > 1; 127 return tls_delegate.Get().Get()->active_run_loops_.size() > 1;
158 } 128 }
159 129
160 // static 130 // static
161 void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) { 131 void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
162 tls_run_loop_state.Get().GetNestingObservers().AddObserver(observer); 132 Delegate* delegate = tls_delegate.Get().Get();
133 CHECK(delegate->allow_nesting_);
134 delegate->nesting_observers_.AddObserver(observer);
163 } 135 }
164 136
165 // static 137 // static
166 void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) { 138 void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
167 tls_run_loop_state.Get().GetNestingObservers().RemoveObserver(observer); 139 Delegate* delegate = tls_delegate.Get().Get();
140 CHECK(delegate->allow_nesting_);
141 delegate->nesting_observers_.RemoveObserver(observer);
168 } 142 }
169 143
170 // static 144 // static
171 bool RunLoop::IsNestingAllowedOnCurrentThread() { 145 bool RunLoop::IsNestingAllowedOnCurrentThread() {
172 return tls_run_loop_state.Get().IsNestingAllowed(); 146 return tls_delegate.Get().Get()->allow_nesting_;
173 } 147 }
174 148
175 // static 149 // static
176 void RunLoop::DisallowNestingOnCurrentThread() { 150 void RunLoop::DisallowNestingOnCurrentThread() {
177 tls_run_loop_state.Get().DisallowNesting(); 151 tls_delegate.Get().Get()->allow_nesting_ = false;
178 } 152 }
179 153
180 bool RunLoop::BeforeRun() { 154 bool RunLoop::BeforeRun() {
181 DCHECK(thread_checker_.CalledOnValidThread()); 155 DCHECK(thread_checker_.CalledOnValidThread());
182 156
183 DCHECK(!run_called_); 157 DCHECK(!run_called_);
184 run_called_ = true; 158 run_called_ = true;
185 159
186 // Allow Quit to be called before Run. 160 // Allow Quit to be called before Run.
187 if (quit_called_) 161 if (quit_called_)
188 return false; 162 return false;
189 163
190 auto& active_run_loops = tls_run_loop_state.Get().GetActiveRunLoops(); 164 auto& active_run_loops_ = delegate_->active_run_loops_;
191 active_run_loops.push(this); 165 active_run_loops_.push(this);
192 166
193 const bool is_nested = active_run_loops.size() > 1; 167 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
197 loop_->run_loop_ = this;
198 loop_->is_nested_ = is_nested;
199 168
200 if (is_nested) { 169 if (is_nested) {
201 CHECK(tls_run_loop_state.Get().IsNestingAllowed()); 170 CHECK(delegate_->allow_nesting_);
202 for (auto& observer : tls_run_loop_state.Get().GetNestingObservers()) 171 for (auto& observer : delegate_->nesting_observers_)
203 observer.OnBeginNestedRunLoop(); 172 observer.OnBeginNestedRunLoop();
204 } 173 }
205 174
206 running_ = true; 175 running_ = true;
207 return true; 176 return true;
208 } 177 }
209 178
210 void RunLoop::AfterRun() { 179 void RunLoop::AfterRun() {
211 DCHECK(thread_checker_.CalledOnValidThread()); 180 DCHECK(thread_checker_.CalledOnValidThread());
212 181
213 running_ = false; 182 running_ = false;
214 183
215 auto& active_run_loops = tls_run_loop_state.Get().GetActiveRunLoops(); 184 auto& active_run_loops_ = delegate_->active_run_loops_;
216 DCHECK_EQ(active_run_loops.top(), this); 185 DCHECK_EQ(active_run_loops_.top(), this);
217 active_run_loops.pop(); 186 active_run_loops_.pop();
218 187
219 RunLoop* previous_run_loop = 188 RunLoop* previous_run_loop =
220 active_run_loops.empty() ? nullptr : active_run_loops.top(); 189 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;
223 190
224 // Execute deferred QuitNow, if any: 191 // Execute deferred QuitNow, if any:
225 if (previous_run_loop && previous_run_loop->quit_called_) 192 if (previous_run_loop && previous_run_loop->quit_called_)
226 loop_->QuitNow(); 193 delegate_->Quit();
227 } 194 }
228 195
229 } // namespace base 196 } // namespace base
OLDNEW
« base/run_loop.h ('K') | « base/run_loop.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698