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