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 3 // found in the LICENSE file. 4 5 #include "base/threading/thread.h" 6 7 #include "base/bind.h" 8 #include "base/lazy_instance.h" 9 #include "base/location.h" 10 #include "base/run_loop.h" 11 #include "base/synchronization/waitable_event.h" 12 #include "base/threading/thread_id_name_manager.h" 13 #include "base/threading/thread_local.h" 14 #include "base/threading/thread_restrictions.h" 15 #include "build/build_config.h" 16 17 #if defined(OS_WIN) 18 #include "base/win/scoped_com_initializer.h" 19 #endif 20 21 namespace base { 22 23 namespace { 24 25 // We use this thread-local variable to record whether or not a thread exited 26 // because its Stop method was called. This allows us to catch cases where 27 // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when 28 // using a Thread to setup and run a MessageLoop. 29 base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool = 30 LAZY_INSTANCE_INITIALIZER; 31 32 } // namespace 33 34 // This is used to trigger the message loop to exit. 35 void ThreadQuitHelper() { 36 MessageLoop::current()->QuitWhenIdle(); 37 Thread::SetThreadWasQuitProperly(true); 38 } 39 40 Thread::Options::Options() 41 : message_loop_type(MessageLoop::TYPE_DEFAULT), 42 timer_slack(TIMER_SLACK_NONE), 43 stack_size(0), 44 priority(ThreadPriority::NORMAL) { 45 } 46 47 Thread::Options::Options(MessageLoop::Type type, 48 size_t size) 49 : message_loop_type(type), 50 timer_slack(TIMER_SLACK_NONE), 51 stack_size(size), 52 priority(ThreadPriority::NORMAL) { 53 } 54 55 Thread::Options::Options(const Options& other) = default; 56 57 Thread::Options::~Options() { 58 } 59 60 Thread::Thread(const std::string& name) 61 : 62 #if defined(OS_WIN) 63 com_status_(NONE), 64 #endif 65 stopping_(false), 66 running_(false), 67 thread_(0), 68 id_(kInvalidThreadId), 69 id_event_(WaitableEvent::ResetPolicy::MANUAL, 70 WaitableEvent::InitialState::NOT_SIGNALED), 71 message_loop_(nullptr), 72 message_loop_timer_slack_(TIMER_SLACK_NONE), 73 name_(name), 74 start_event_(WaitableEvent::ResetPolicy::MANUAL, 75 WaitableEvent::InitialState::NOT_SIGNALED) { 76 } 77 78 Thread::~Thread() { 79 Stop(); 80 } 81 82 bool Thread::Start() { 83 Options options; 84 #if defined(OS_WIN) 85 if (com_status_ == STA) 86 options.message_loop_type = MessageLoop::TYPE_UI; 87 #endif 88 return StartWithOptions(options); 89 } 90 91 bool Thread::StartWithOptions(const Options& options) { 92 DCHECK(!message_loop_); 93 #if defined(OS_WIN) 94 DCHECK((com_status_ != STA) || 95 (options.message_loop_type == MessageLoop::TYPE_UI)); 96 #endif 97 98 // Reset |id_| here to support restarting the thread. 99 id_event_.Reset(); 100 id_ = kInvalidThreadId; 101 102 SetThreadWasQuitProperly(false); 103 104 MessageLoop::Type type = options.message_loop_type; 105 if (!options.message_pump_factory.is_null()) 106 type = MessageLoop::TYPE_CUSTOM; 107 108 message_loop_timer_slack_ = options.timer_slack; 109 std::unique_ptr<MessageLoop> message_loop = 110 MessageLoop::CreateUnbound(type, options.message_pump_factory); 111 message_loop_ = message_loop.get(); 112 start_event_.Reset(); 113 114 // Hold the thread_lock_ while starting a new thread, so that we can make sure 115 // that thread_ is populated before the newly created thread accesses it. 116 { 117 AutoLock lock(thread_lock_); 118 if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_, 119 options.priority)) { 120 DLOG(ERROR) << "failed to create thread"; 121 message_loop_ = nullptr; 122 return false; 123 } 124 } 125 126 // The ownership of message_loop is managemed by the newly created thread 127 // within the ThreadMain. 128 ignore_result(message_loop.release()); 129 130 DCHECK(message_loop_); 131 return true; 132 } 133 134 bool Thread::StartAndWaitForTesting() { 135 bool result = Start(); 136 if (!result) 137 return false; 138 WaitUntilThreadStarted(); 139 return true; 140 } 141 142 bool Thread::WaitUntilThreadStarted() const { 143 if (!message_loop_) 144 return false; 145 base::ThreadRestrictions::ScopedAllowWait allow_wait; 146 start_event_.Wait(); 147 return true; 148 } 149 150 void Thread::Stop() { 151 AutoLock lock(thread_lock_); 152 if (thread_.is_null()) 153 return; 154 155 StopSoon(); 156 157 // Wait for the thread to exit. 158 // 159 // TODO(darin): Unfortunately, we need to keep message_loop_ around until 160 // the thread exits. Some consumers are abusing the API. Make them stop. 161 // 162 PlatformThread::Join(thread_); 163 thread_ = base::PlatformThreadHandle(); 164 165 // The thread should nullify message_loop_ on exit. 166 DCHECK(!message_loop_); 167 168 stopping_ = false; 169 } 170 171 void Thread::StopSoon() { 172 // We should only be called on the same thread that started us. 173 174 DCHECK_NE(GetThreadId(), PlatformThread::CurrentId()); 175 176 if (stopping_ || !message_loop_) 177 return; 178 179 stopping_ = true; 180 task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper)); 181 } 182 183 PlatformThreadId Thread::GetThreadId() const { 184 // If the thread is created but not started yet, wait for |id_| being ready. 185 base::ThreadRestrictions::ScopedAllowWait allow_wait; 186 id_event_.Wait(); 187 return id_; 188 } 189 190 bool Thread::IsRunning() const { 191 // If the thread's already started (i.e. message_loop_ is non-null) and 192 // not yet requested to stop (i.e. stopping_ is false) we can just return 193 // true. (Note that stopping_ is touched only on the same thread that 194 // starts / started the new thread so we need no locking here.) 195 if (message_loop_ && !stopping_) 196 return true; 197 // Otherwise check the running_ flag, which is set to true by the new thread 198 // only while it is inside Run(). 199 AutoLock lock(running_lock_); 200 return running_; 201 } 202 203 void Thread::Run(MessageLoop*) { 204 RunLoop().Run(); 205 } 206 207 void Thread::SetThreadWasQuitProperly(bool flag) { 208 lazy_tls_bool.Pointer()->Set(flag); 209 } 210 211 bool Thread::GetThreadWasQuitProperly() { 212 bool quit_properly = true; 213 #ifndef NDEBUG 214 quit_properly = lazy_tls_bool.Pointer()->Get(); 215 #endif 216 return quit_properly; 217 } 218 219 void Thread::ThreadMain() { 220 // First, make GetThreadId() available to avoid deadlocks. It could be called 221 // any place in the following thread initialization code. 222 id_ = PlatformThread::CurrentId(); 223 DCHECK_NE(kInvalidThreadId, id_); 224 id_event_.Signal(); 225 226 // Complete the initialization of our Thread object. 227 PlatformThread::SetName(name_.c_str()); 228 229 // Lazily initialize the message_loop so that it can run on this thread. 230 DCHECK(message_loop_); 231 std::unique_ptr<MessageLoop> message_loop(message_loop_); 232 message_loop_->BindToCurrentThread(); 233 message_loop_->SetTimerSlack(message_loop_timer_slack_); 234 235 #if defined(OS_WIN) 236 std::unique_ptr<win::ScopedCOMInitializer> com_initializer; 237 if (com_status_ != NONE) { 238 com_initializer.reset((com_status_ == STA) ? 239 new win::ScopedCOMInitializer() : 240 new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA)); 241 } 242 #endif 243 244 // Let the thread do extra initialization. 245 Init(); 246 247 { 248 AutoLock lock(running_lock_); 249 running_ = true; 250 } 251 252 start_event_.Signal(); 253 254 Run(message_loop_); 255 256 { 257 AutoLock lock(running_lock_); 258 running_ = false; 259 } 260 261 // Let the thread do extra cleanup. 262 CleanUp(); 263 264 #if defined(OS_WIN) 265 com_initializer.reset(); 266 #endif 267 268 if (message_loop->type() != MessageLoop::TYPE_CUSTOM) { 269 // Assert that MessageLoop::QuitWhenIdle was called by ThreadQuitHelper. 270 // Don't check for custom message pumps, because their shutdown might not 271 // allow this. 272 DCHECK(GetThreadWasQuitProperly()); 273 } 274 275 // We can't receive messages anymore. 276 // (The message loop is destructed at the end of this block) 277 message_loop_ = nullptr; 278 } 279 280 } // namespace base 281