OLD | NEW |
---|---|
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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/lazy_instance.h" | 8 #include "base/lazy_instance.h" |
9 #include "base/threading/thread_local.h" | 9 #include "base/threading/thread_local.h" |
10 #include "base/tracked_objects.h" | 10 #include "base/tracked_objects.h" |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
63 return &delegate->client_interface_; | 63 return &delegate->client_interface_; |
64 } | 64 } |
65 | 65 |
66 RunLoop::RunLoop() : delegate_(tls_delegate.Get().Get()), weak_factory_(this) { | 66 RunLoop::RunLoop() : delegate_(tls_delegate.Get().Get()), weak_factory_(this) { |
67 // A RunLoop::Delegate must be bound to this thread prior to using RunLoop. | 67 // A RunLoop::Delegate must be bound to this thread prior to using RunLoop. |
68 DCHECK(delegate_); | 68 DCHECK(delegate_); |
69 } | 69 } |
70 | 70 |
71 RunLoop::~RunLoop() { | 71 RunLoop::~RunLoop() { |
72 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. | 72 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. |
73 // DCHECK(thread_checker_.CalledOnValidThread()); | 73 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
74 } | 74 } |
75 | 75 |
76 void RunLoop::Run() { | 76 void RunLoop::Run() { |
77 DCHECK(thread_checker_.CalledOnValidThread()); | 77 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
78 | 78 |
79 if (!BeforeRun()) | 79 if (!BeforeRun()) |
80 return; | 80 return; |
81 | 81 |
82 // It is okay to access this RunLoop from another sequence while Run() is | |
83 // active as this RunLoop won't touch its state until after that returns (if | |
84 // the RunLoop's state is accessed while processing Run(), it will be re-bound | |
85 // to the accessing sequence for the remainder of that Run() -- accessing from | |
86 // multiple sequences is still disallowed). | |
87 DETACH_FROM_SEQUENCE(sequence_checker_); | |
88 | |
82 // Use task stopwatch to exclude the loop run time from the current task, if | 89 // Use task stopwatch to exclude the loop run time from the current task, if |
83 // any. | 90 // any. |
84 tracked_objects::TaskStopwatch stopwatch; | 91 tracked_objects::TaskStopwatch stopwatch; |
85 stopwatch.Start(); | 92 stopwatch.Start(); |
86 delegate_->Run(); | 93 delegate_->Run(); |
87 stopwatch.Stop(); | 94 stopwatch.Stop(); |
88 | 95 |
96 // Rebind this RunLoop to the current thread after Run(). | |
danakj
2017/05/18 15:25:27
current sequence?
gab
2017/05/18 16:14:02
I debated that but in practice RunLoop always runs
| |
97 DETACH_FROM_SEQUENCE(sequence_checker_); | |
98 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
99 | |
89 AfterRun(); | 100 AfterRun(); |
90 } | 101 } |
91 | 102 |
92 void RunLoop::RunUntilIdle() { | 103 void RunLoop::RunUntilIdle() { |
93 DCHECK(thread_checker_.CalledOnValidThread()); | 104 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
94 | 105 |
95 quit_when_idle_received_ = true; | 106 quit_when_idle_received_ = true; |
96 Run(); | 107 Run(); |
97 } | 108 } |
98 | 109 |
99 void RunLoop::Quit() { | 110 void RunLoop::Quit() { |
100 DCHECK(thread_checker_.CalledOnValidThread()); | 111 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
101 | 112 |
102 quit_called_ = true; | 113 quit_called_ = true; |
103 if (running_ && delegate_->active_run_loops_.top() == this) { | 114 if (running_ && delegate_->active_run_loops_.top() == this) { |
104 // This is the inner-most RunLoop, so quit now. | 115 // This is the inner-most RunLoop, so quit now. |
105 delegate_->Quit(); | 116 delegate_->Quit(); |
106 } | 117 } |
107 } | 118 } |
108 | 119 |
109 void RunLoop::QuitWhenIdle() { | 120 void RunLoop::QuitWhenIdle() { |
110 DCHECK(thread_checker_.CalledOnValidThread()); | 121 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
111 quit_when_idle_received_ = true; | 122 quit_when_idle_received_ = true; |
112 } | 123 } |
113 | 124 |
114 base::Closure RunLoop::QuitClosure() { | 125 base::Closure RunLoop::QuitClosure() { |
115 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. | 126 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. |
116 // DCHECK(thread_checker_.CalledOnValidThread()); | 127 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
117 return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()); | 128 return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()); |
118 } | 129 } |
119 | 130 |
120 base::Closure RunLoop::QuitWhenIdleClosure() { | 131 base::Closure RunLoop::QuitWhenIdleClosure() { |
121 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. | 132 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. |
122 // DCHECK(thread_checker_.CalledOnValidThread()); | 133 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
123 return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()); | 134 return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()); |
124 } | 135 } |
125 | 136 |
126 // static | 137 // static |
127 bool RunLoop::IsRunningOnCurrentThread() { | 138 bool RunLoop::IsRunningOnCurrentThread() { |
128 Delegate* delegate = tls_delegate.Get().Get(); | 139 Delegate* delegate = tls_delegate.Get().Get(); |
129 return delegate && !delegate->active_run_loops_.empty(); | 140 return delegate && !delegate->active_run_loops_.empty(); |
130 } | 141 } |
131 | 142 |
132 // static | 143 // static |
(...skipping 22 matching lines...) Expand all Loading... | |
155 bool RunLoop::IsNestingAllowedOnCurrentThread() { | 166 bool RunLoop::IsNestingAllowedOnCurrentThread() { |
156 return tls_delegate.Get().Get()->allow_nesting_; | 167 return tls_delegate.Get().Get()->allow_nesting_; |
157 } | 168 } |
158 | 169 |
159 // static | 170 // static |
160 void RunLoop::DisallowNestingOnCurrentThread() { | 171 void RunLoop::DisallowNestingOnCurrentThread() { |
161 tls_delegate.Get().Get()->allow_nesting_ = false; | 172 tls_delegate.Get().Get()->allow_nesting_ = false; |
162 } | 173 } |
163 | 174 |
164 bool RunLoop::BeforeRun() { | 175 bool RunLoop::BeforeRun() { |
165 DCHECK(thread_checker_.CalledOnValidThread()); | 176 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
166 | 177 |
167 DCHECK(!run_called_); | 178 DCHECK(!run_called_); |
168 run_called_ = true; | 179 run_called_ = true; |
169 | 180 |
170 // Allow Quit to be called before Run. | 181 // Allow Quit to be called before Run. |
171 if (quit_called_) | 182 if (quit_called_) |
172 return false; | 183 return false; |
173 | 184 |
174 auto& active_run_loops_ = delegate_->active_run_loops_; | 185 auto& active_run_loops_ = delegate_->active_run_loops_; |
175 active_run_loops_.push(this); | 186 active_run_loops_.push(this); |
176 | 187 |
177 const bool is_nested = active_run_loops_.size() > 1; | 188 const bool is_nested = active_run_loops_.size() > 1; |
178 | 189 |
179 if (is_nested) { | 190 if (is_nested) { |
180 CHECK(delegate_->allow_nesting_); | 191 CHECK(delegate_->allow_nesting_); |
181 for (auto& observer : delegate_->nesting_observers_) | 192 for (auto& observer : delegate_->nesting_observers_) |
182 observer.OnBeginNestedRunLoop(); | 193 observer.OnBeginNestedRunLoop(); |
183 } | 194 } |
184 | 195 |
185 running_ = true; | 196 running_ = true; |
186 return true; | 197 return true; |
187 } | 198 } |
188 | 199 |
189 void RunLoop::AfterRun() { | 200 void RunLoop::AfterRun() { |
190 DCHECK(thread_checker_.CalledOnValidThread()); | 201 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
191 | 202 |
192 running_ = false; | 203 running_ = false; |
193 | 204 |
194 auto& active_run_loops_ = delegate_->active_run_loops_; | 205 auto& active_run_loops_ = delegate_->active_run_loops_; |
195 DCHECK_EQ(active_run_loops_.top(), this); | 206 DCHECK_EQ(active_run_loops_.top(), this); |
196 active_run_loops_.pop(); | 207 active_run_loops_.pop(); |
197 | 208 |
198 RunLoop* previous_run_loop = | 209 RunLoop* previous_run_loop = |
199 active_run_loops_.empty() ? nullptr : active_run_loops_.top(); | 210 active_run_loops_.empty() ? nullptr : active_run_loops_.top(); |
200 | 211 |
201 // Execute deferred QuitNow, if any: | 212 // Execute deferred QuitNow, if any: |
202 if (previous_run_loop && previous_run_loop->quit_called_) | 213 if (previous_run_loop && previous_run_loop->quit_called_) |
203 delegate_->Quit(); | 214 delegate_->Quit(); |
204 } | 215 } |
205 | 216 |
206 } // namespace base | 217 } // namespace base |
OLD | NEW |