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