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/third_party/dynamic_annotations/dynamic_annotations.h" 10 #include "base/threading/thread_id_name_manager.h" 11 #include "base/threading/thread_local.h" 12 #include "base/threading/thread_restrictions.h" 13 #include "base/synchronization/waitable_event.h" 14 15 #if defined(OS_WIN) 16 #include "base/win/scoped_com_initializer.h" 17 #endif 18 19 namespace base { 20 21 namespace { 22 23 // We use this thread-local variable to record whether or not a thread exited 24 // because its Stop method was called. This allows us to catch cases where 25 // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when 26 // using a Thread to setup and run a MessageLoop. 27 base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool = 28 LAZY_INSTANCE_INITIALIZER; 29 30 } // namespace 31 32 // This is used to trigger the message loop to exit. 33 void ThreadQuitHelper() { 34 MessageLoop::current()->QuitWhenIdle(); 35 Thread::SetThreadWasQuitProperly(true); 36 } 37 38 // Used to pass data to ThreadMain. This structure is allocated on the stack 39 // from within StartWithOptions. 40 struct Thread::StartupData { 41 // We get away with a const reference here because of how we are allocated. 42 const Thread::Options& options; 43 44 // Used to synchronize thread startup. 45 WaitableEvent event; 46 47 explicit StartupData(const Options& opt) 48 : options(opt), 49 event(false, false) {} 50 }; 51 52 Thread::Options::Options() 53 : message_loop_type(MessageLoop::TYPE_DEFAULT), 54 stack_size(0) { 55 } 56 57 Thread::Options::Options(MessageLoop::Type type, 58 size_t size) 59 : message_loop_type(type), 60 stack_size(size) { 61 } 62 63 Thread::Options::~Options() { 64 } 65 66 Thread::Thread(const char* name) 67 : 68 #if defined(OS_WIN) 69 com_status_(NONE), 70 #endif 71 started_(false), 72 stopping_(false), 73 running_(false), 74 startup_data_(NULL), 75 thread_(0), 76 message_loop_(NULL), 77 thread_id_(kInvalidThreadId), 78 name_(name) { 79 } 80 81 Thread::~Thread() { 82 Stop(); 83 } 84 85 bool Thread::Start() { 86 Options options; 87 #if defined(OS_WIN) 88 if (com_status_ == STA) 89 options.message_loop_type = MessageLoop::TYPE_UI; 90 #endif 91 return StartWithOptions(options); 92 } 93 94 bool Thread::StartWithOptions(const Options& options) { 95 DCHECK(!message_loop_); 96 #if defined(OS_WIN) 97 DCHECK((com_status_ != STA) || 98 (options.message_loop_type == MessageLoop::TYPE_UI)); 99 #endif 100 101 SetThreadWasQuitProperly(false); 102 103 StartupData startup_data(options); 104 startup_data_ = &startup_data; 105 106 if (!PlatformThread::Create(options.stack_size, this, &thread_)) { 107 DLOG(ERROR) << "failed to create thread"; 108 startup_data_ = NULL; 109 return false; 110 } 111 112 // Wait for the thread to start and initialize message_loop_ 113 base::ThreadRestrictions::ScopedAllowWait allow_wait; 114 startup_data.event.Wait(); 115 116 // set it to NULL so we don't keep a pointer to some object on the stack. 117 startup_data_ = NULL; 118 started_ = true; 119 120 DCHECK(message_loop_); 121 return true; 122 } 123 124 void Thread::Stop() { 125 if (!started_) 126 return; 127 128 StopSoon(); 129 130 // Wait for the thread to exit. 131 // 132 // TODO(darin): Unfortunately, we need to keep message_loop_ around until 133 // the thread exits. Some consumers are abusing the API. Make them stop. 134 // 135 PlatformThread::Join(thread_); 136 137 // The thread should NULL message_loop_ on exit. 138 DCHECK(!message_loop_); 139 140 // The thread no longer needs to be joined. 141 started_ = false; 142 143 stopping_ = false; 144 } 145 146 void Thread::StopSoon() { 147 // We should only be called on the same thread that started us. 148 149 // Reading thread_id_ without a lock can lead to a benign data race 150 // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer. 151 DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId()); 152 153 if (stopping_ || !message_loop_) 154 return; 155 156 stopping_ = true; 157 message_loop_->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper)); 158 } 159 160 bool Thread::IsRunning() const { 161 return running_; 162 } 163 164 void Thread::SetPriority(ThreadPriority priority) { 165 // The thread must be started (and id known) for this to be 166 // compatible with all platforms. 167 DCHECK_NE(thread_id_, kInvalidThreadId); 168 PlatformThread::SetThreadPriority(thread_, priority); 169 } 170 171 void Thread::Run(MessageLoop* message_loop) { 172 message_loop->Run(); 173 } 174 175 void Thread::SetThreadWasQuitProperly(bool flag) { 176 lazy_tls_bool.Pointer()->Set(flag); 177 } 178 179 bool Thread::GetThreadWasQuitProperly() { 180 bool quit_properly = true; 181 #ifndef NDEBUG 182 quit_properly = lazy_tls_bool.Pointer()->Get(); 183 #endif 184 return quit_properly; 185 } 186 187 void Thread::ThreadMain() { 188 { 189 // The message loop for this thread. 190 // Allocated on the heap to centralize any leak reports at this line. 191 scoped_ptr<MessageLoop> message_loop; 192 if (!startup_data_->options.message_pump_factory.is_null()) { 193 message_loop.reset( 194 new MessageLoop(startup_data_->options.message_pump_factory.Run())); 195 } else { 196 message_loop.reset( 197 new MessageLoop(startup_data_->options.message_loop_type)); 198 } 199 200 // Complete the initialization of our Thread object. 201 thread_id_ = PlatformThread::CurrentId(); 202 PlatformThread::SetName(name_.c_str()); 203 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector. 204 message_loop->set_thread_name(name_); 205 message_loop_ = message_loop.get(); 206 207 #if defined(OS_WIN) 208 scoped_ptr<win::ScopedCOMInitializer> com_initializer; 209 if (com_status_ != NONE) { 210 com_initializer.reset((com_status_ == STA) ? 211 new win::ScopedCOMInitializer() : 212 new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA)); 213 } 214 #endif 215 216 // Let the thread do extra initialization. 217 // Let's do this before signaling we are started. 218 Init(); 219 220 running_ = true; 221 startup_data_->event.Signal(); 222 // startup_data_ can't be touched anymore since the starting thread is now 223 // unlocked. 224 225 Run(message_loop_); 226 running_ = false; 227 228 // Let the thread do extra cleanup. 229 CleanUp(); 230 231 #if defined(OS_WIN) 232 com_initializer.reset(); 233 #endif 234 235 // Assert that MessageLoop::Quit was called by ThreadQuitHelper. 236 DCHECK(GetThreadWasQuitProperly()); 237 238 // We can't receive messages anymore. 239 message_loop_ = NULL; 240 } 241 } 242 243 } // namespace base 244