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

Side by Side Diff: base/run_loop.cc

Issue 2886913003: Loosen thread-safety checks and update documentation on RunLoop. (Closed)
Patch Set: proper dependency 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') | 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 "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
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
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
OLDNEW
« no previous file with comments | « base/run_loop.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698