| 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 |