1 // Copyright (c) 2006-2009 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/lazy_instance.h" 8 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 9 #include "base/threading/thread_local.h" 10 #include "base/synchronization/waitable_event.h" 11 12 namespace base { 13 14 namespace { 15 16 // We use this thread-local variable to record whether or not a thread exited 17 // because its Stop method was called. This allows us to catch cases where 18 // MessageLoop::Quit() is called directly, which is unexpected when using a 19 // Thread to setup and run a MessageLoop. 20 base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool( 21 base::LINKER_INITIALIZED); 22 23 } // namespace 24 25 // This task is used to trigger the message loop to exit. 26 class ThreadQuitTask : public Task { 27 public: 28 virtual void Run() { 29 MessageLoop::current()->Quit(); 30 Thread::SetThreadWasQuitProperly(true); 31 } 32 }; 33 34 // Used to pass data to ThreadMain. This structure is allocated on the stack 35 // from within StartWithOptions. 36 struct Thread::StartupData { 37 // We get away with a const reference here because of how we are allocated. 38 const Thread::Options& options; 39 40 // Used to synchronize thread startup. 41 WaitableEvent event; 42 43 explicit StartupData(const Options& opt) 44 : options(opt), 45 event(false, false) {} 46 }; 47 48 Thread::Thread(const char* name) 49 : started_(false), 50 stopping_(false), 51 startup_data_(NULL), 52 thread_(0), 53 message_loop_(NULL), 54 thread_id_(kInvalidThreadId), 55 name_(name) { 56 } 57 58 Thread::~Thread() { 59 Stop(); 60 } 61 62 bool Thread::Start() { 63 return StartWithOptions(Options()); 64 } 65 66 bool Thread::StartWithOptions(const Options& options) { 67 DCHECK(!message_loop_); 68 69 SetThreadWasQuitProperly(false); 70 71 StartupData startup_data(options); 72 startup_data_ = &startup_data; 73 74 if (!PlatformThread::Create(options.stack_size, this, &thread_)) { 75 DLOG(ERROR) << "failed to create thread"; 76 startup_data_ = NULL; 77 return false; 78 } 79 80 // Wait for the thread to start and initialize message_loop_ 81 startup_data.event.Wait(); 82 83 // set it to NULL so we don't keep a pointer to some object on the stack. 84 startup_data_ = NULL; 85 started_ = true; 86 87 DCHECK(message_loop_); 88 return true; 89 } 90 91 void Thread::Stop() { 92 if (!thread_was_started()) 93 return; 94 95 StopSoon(); 96 97 // Wait for the thread to exit. 98 // 99 // TODO(darin): Unfortunately, we need to keep message_loop_ around until 100 // the thread exits. Some consumers are abusing the API. Make them stop. 101 // 102 PlatformThread::Join(thread_); 103 104 // The thread should NULL message_loop_ on exit. 105 DCHECK(!message_loop_); 106 107 // The thread no longer needs to be joined. 108 started_ = false; 109 110 stopping_ = false; 111 } 112 113 void Thread::StopSoon() { 114 // We should only be called on the same thread that started us. 115 116 // Reading thread_id_ without a lock can lead to a benign data race 117 // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer. 118 DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId()); 119 120 if (stopping_ || !message_loop_) 121 return; 122 123 stopping_ = true; 124 message_loop_->PostTask(FROM_HERE, new ThreadQuitTask()); 125 } 126 127 void Thread::Run(MessageLoop* message_loop) { 128 message_loop->Run(); 129 } 130 131 void Thread::SetThreadWasQuitProperly(bool flag) { 132 lazy_tls_bool.Pointer()->Set(flag); 133 } 134 135 bool Thread::GetThreadWasQuitProperly() { 136 bool quit_properly = true; 137 #ifndef NDEBUG 138 quit_properly = lazy_tls_bool.Pointer()->Get(); 139 #endif 140 return quit_properly; 141 } 142 143 void Thread::ThreadMain() { 144 { 145 // The message loop for this thread. 146 MessageLoop message_loop(startup_data_->options.message_loop_type); 147 148 // Complete the initialization of our Thread object. 149 thread_id_ = PlatformThread::CurrentId(); 150 PlatformThread::SetName(name_.c_str()); 151 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector. 152 message_loop.set_thread_name(name_); 153 message_loop_ = &message_loop; 154 message_loop_proxy_ = MessageLoopProxy::CreateForCurrentThread(); 155 156 // Let the thread do extra initialization. 157 // Let's do this before signaling we are started. 158 Init(); 159 160 startup_data_->event.Signal(); 161 // startup_data_ can't be touched anymore since the starting thread is now 162 // unlocked. 163 164 Run(message_loop_); 165 166 // Let the thread do extra cleanup. 167 CleanUp(); 168 169 // Assert that MessageLoop::Quit was called by ThreadQuitTask. 170 DCHECK(GetThreadWasQuitProperly()); 171 172 // We can't receive messages anymore. 173 message_loop_ = NULL; 174 message_loop_proxy_ = NULL; 175 } 176 thread_id_ = kInvalidThreadId; 177 } 178 179 } // namespace base 180