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/threading/thread.h" | 5 #include "base/threading/thread.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" |
8 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
9 #include "base/location.h" | 10 #include "base/location.h" |
10 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
11 #include "base/synchronization/waitable_event.h" | 12 #include "base/synchronization/waitable_event.h" |
12 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 13 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
13 #include "base/threading/thread_id_name_manager.h" | 14 #include "base/threading/thread_id_name_manager.h" |
14 #include "base/threading/thread_local.h" | 15 #include "base/threading/thread_local.h" |
15 #include "base/threading/thread_restrictions.h" | 16 #include "base/threading/thread_restrictions.h" |
16 #include "build/build_config.h" | 17 #include "build/build_config.h" |
17 | 18 |
18 #if defined(OS_WIN) | 19 #if defined(OS_WIN) |
19 #include "base/win/scoped_com_initializer.h" | 20 #include "base/win/scoped_com_initializer.h" |
20 #endif | 21 #endif |
21 | 22 |
22 namespace base { | 23 namespace base { |
23 | 24 |
24 namespace { | 25 namespace { |
25 | 26 |
26 // We use this thread-local variable to record whether or not a thread exited | 27 // We use this thread-local variable to record whether or not a thread exited |
27 // because its Stop method was called. This allows us to catch cases where | 28 // because its Stop method was called. This allows us to catch cases where |
28 // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when | 29 // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when |
29 // using a Thread to setup and run a MessageLoop. | 30 // using a Thread to setup and run a MessageLoop. |
30 base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool = | 31 base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool = |
31 LAZY_INSTANCE_INITIALIZER; | 32 LAZY_INSTANCE_INITIALIZER; |
32 | 33 |
33 } // namespace | 34 } // namespace |
34 | 35 |
35 // This is used to trigger the message loop to exit. | |
36 void ThreadQuitHelper() { | |
37 MessageLoop::current()->QuitWhenIdle(); | |
38 Thread::SetThreadWasQuitProperly(true); | |
39 } | |
40 | |
41 Thread::Options::Options() | 36 Thread::Options::Options() |
42 : message_loop_type(MessageLoop::TYPE_DEFAULT), | 37 : message_loop_type(MessageLoop::TYPE_DEFAULT), |
43 timer_slack(TIMER_SLACK_NONE), | 38 timer_slack(TIMER_SLACK_NONE), |
44 stack_size(0), | 39 stack_size(0), |
45 priority(ThreadPriority::NORMAL) { | 40 priority(ThreadPriority::NORMAL) { |
46 } | 41 } |
47 | 42 |
48 Thread::Options::Options(MessageLoop::Type type, | 43 Thread::Options::Options(MessageLoop::Type type, |
49 size_t size) | 44 size_t size) |
50 : message_loop_type(type), | 45 : message_loop_type(type), |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 | 166 |
172 void Thread::StopSoon() { | 167 void Thread::StopSoon() { |
173 // We should only be called on the same thread that started us. | 168 // We should only be called on the same thread that started us. |
174 | 169 |
175 DCHECK_NE(GetThreadId(), PlatformThread::CurrentId()); | 170 DCHECK_NE(GetThreadId(), PlatformThread::CurrentId()); |
176 | 171 |
177 if (stopping_ || !message_loop_) | 172 if (stopping_ || !message_loop_) |
178 return; | 173 return; |
179 | 174 |
180 stopping_ = true; | 175 stopping_ = true; |
181 task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper)); | 176 task_runner()->PostTask( |
| 177 FROM_HERE, base::Bind(&Thread::ThreadQuitHelper, Unretained(this))); |
182 } | 178 } |
183 | 179 |
184 PlatformThreadId Thread::GetThreadId() const { | 180 PlatformThreadId Thread::GetThreadId() const { |
185 // If the thread is created but not started yet, wait for |id_| being ready. | 181 // If the thread is created but not started yet, wait for |id_| being ready. |
186 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 182 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
187 id_event_.Wait(); | 183 id_event_.Wait(); |
188 return id_; | 184 return id_; |
189 } | 185 } |
190 | 186 |
191 bool Thread::IsRunning() const { | 187 bool Thread::IsRunning() const { |
192 // If the thread's already started (i.e. message_loop_ is non-null) and | 188 // If the thread's already started (i.e. message_loop_ is non-null) and |
193 // not yet requested to stop (i.e. stopping_ is false) we can just return | 189 // not yet requested to stop (i.e. stopping_ is false) we can just return |
194 // true. (Note that stopping_ is touched only on the same thread that | 190 // true. (Note that stopping_ is touched only on the same thread that |
195 // starts / started the new thread so we need no locking here.) | 191 // starts / started the new thread so we need no locking here.) |
196 if (message_loop_ && !stopping_) | 192 if (message_loop_ && !stopping_) |
197 return true; | 193 return true; |
198 // Otherwise check the running_ flag, which is set to true by the new thread | 194 // Otherwise check the running_ flag, which is set to true by the new thread |
199 // only while it is inside Run(). | 195 // only while it is inside Run(). |
200 AutoLock lock(running_lock_); | 196 AutoLock lock(running_lock_); |
201 return running_; | 197 return running_; |
202 } | 198 } |
203 | 199 |
204 void Thread::Run(MessageLoop* message_loop) { | 200 void Thread::Run(RunLoop* run_loop) { |
205 RunLoop().Run(); | 201 run_loop->Run(); |
206 } | 202 } |
207 | 203 |
208 void Thread::SetThreadWasQuitProperly(bool flag) { | 204 void Thread::SetThreadWasQuitProperly(bool flag) { |
209 lazy_tls_bool.Pointer()->Set(flag); | 205 lazy_tls_bool.Pointer()->Set(flag); |
210 } | 206 } |
211 | 207 |
212 bool Thread::GetThreadWasQuitProperly() { | 208 bool Thread::GetThreadWasQuitProperly() { |
213 bool quit_properly = true; | 209 bool quit_properly = true; |
214 #ifndef NDEBUG | 210 #ifndef NDEBUG |
215 quit_properly = lazy_tls_bool.Pointer()->Get(); | 211 quit_properly = lazy_tls_bool.Pointer()->Get(); |
(...skipping 30 matching lines...) Expand all Loading... |
246 // Let the thread do extra initialization. | 242 // Let the thread do extra initialization. |
247 Init(); | 243 Init(); |
248 | 244 |
249 { | 245 { |
250 AutoLock lock(running_lock_); | 246 AutoLock lock(running_lock_); |
251 running_ = true; | 247 running_ = true; |
252 } | 248 } |
253 | 249 |
254 start_event_.Signal(); | 250 start_event_.Signal(); |
255 | 251 |
256 Run(message_loop_); | 252 RunLoop run_loop; |
| 253 run_loop_ = &run_loop; |
| 254 Run(run_loop_); |
257 | 255 |
258 { | 256 { |
259 AutoLock lock(running_lock_); | 257 AutoLock lock(running_lock_); |
260 running_ = false; | 258 running_ = false; |
261 } | 259 } |
262 | 260 |
263 // Let the thread do extra cleanup. | 261 // Let the thread do extra cleanup. |
264 CleanUp(); | 262 CleanUp(); |
265 | 263 |
266 #if defined(OS_WIN) | 264 #if defined(OS_WIN) |
267 com_initializer.reset(); | 265 com_initializer.reset(); |
268 #endif | 266 #endif |
269 | 267 |
270 if (message_loop->type() != MessageLoop::TYPE_CUSTOM) { | 268 if (message_loop->type() != MessageLoop::TYPE_CUSTOM) { |
271 // Assert that MessageLoop::QuitWhenIdle was called by ThreadQuitHelper. | 269 // Assert that RunLoop::QuitWhenIdle was called by ThreadQuitHelper. Don't |
272 // Don't check for custom message pumps, because their shutdown might not | 270 // check for custom message pumps, because their shutdown might not allow |
273 // allow this. | 271 // this. |
274 DCHECK(GetThreadWasQuitProperly()); | 272 DCHECK(GetThreadWasQuitProperly()); |
275 } | 273 } |
276 | 274 |
277 // We can't receive messages anymore. | 275 // We can't receive messages anymore. |
278 // (The message loop is destructed at the end of this block) | 276 // (The message loop is destructed at the end of this block) |
279 message_loop_ = nullptr; | 277 message_loop_ = nullptr; |
| 278 run_loop_ = nullptr; |
| 279 } |
| 280 |
| 281 void Thread::ThreadQuitHelper() { |
| 282 DCHECK(run_loop_); |
| 283 run_loop_->QuitWhenIdle(); |
| 284 SetThreadWasQuitProperly(true); |
280 } | 285 } |
281 | 286 |
282 } // namespace base | 287 } // namespace base |
OLD | NEW |