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