| OLD | NEW |
| (Empty) |
| 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/lazy_instance.h" | |
| 8 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | |
| 9 #include "base/threading/thread_local.h" | |
| 10 #include "base/waitable_event.h" | |
| 11 | |
| 12 namespace base { | |
| 13 | |
| 14 // This task is used to trigger the message loop to exit. | |
| 15 class ThreadQuitTask : public Task { | |
| 16 public: | |
| 17 virtual void Run() { | |
| 18 MessageLoop::current()->Quit(); | |
| 19 Thread::SetThreadWasQuitProperly(true); | |
| 20 } | |
| 21 }; | |
| 22 | |
| 23 // Used to pass data to ThreadMain. This structure is allocated on the stack | |
| 24 // from within StartWithOptions. | |
| 25 struct Thread::StartupData { | |
| 26 // We get away with a const reference here because of how we are allocated. | |
| 27 const Thread::Options& options; | |
| 28 | |
| 29 // Used to synchronize thread startup. | |
| 30 WaitableEvent event; | |
| 31 | |
| 32 explicit StartupData(const Options& opt) | |
| 33 : options(opt), | |
| 34 event(false, false) {} | |
| 35 }; | |
| 36 | |
| 37 Thread::Thread(const char* name) | |
| 38 : started_(false), | |
| 39 stopping_(false), | |
| 40 startup_data_(NULL), | |
| 41 thread_(0), | |
| 42 message_loop_(NULL), | |
| 43 thread_id_(kInvalidThreadId), | |
| 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; | |
| 89 return false; | |
| 90 } | |
| 91 | |
| 92 // Wait for the thread to start and initialize message_loop_ | |
| 93 startup_data.event.Wait(); | |
| 94 | |
| 95 // set it to NULL so we don't keep a pointer to some object on the stack. | |
| 96 startup_data_ = NULL; | |
| 97 started_ = true; | |
| 98 | |
| 99 DCHECK(message_loop_); | |
| 100 return true; | |
| 101 } | |
| 102 | |
| 103 void Thread::Stop() { | |
| 104 if (!thread_was_started()) | |
| 105 return; | |
| 106 | |
| 107 StopSoon(); | |
| 108 | |
| 109 // Wait for the thread to exit. | |
| 110 // | |
| 111 // TODO(darin): Unfortunately, we need to keep message_loop_ around until | |
| 112 // the thread exits. Some consumers are abusing the API. Make them stop. | |
| 113 // | |
| 114 PlatformThread::Join(thread_); | |
| 115 | |
| 116 // The thread should NULL message_loop_ on exit. | |
| 117 DCHECK(!message_loop_); | |
| 118 | |
| 119 // The thread no longer needs to be joined. | |
| 120 started_ = false; | |
| 121 | |
| 122 stopping_ = false; | |
| 123 } | |
| 124 | |
| 125 void Thread::StopSoon() { | |
| 126 // We should only be called on the same thread that started us. | |
| 127 | |
| 128 // Reading thread_id_ without a lock can lead to a benign data race | |
| 129 // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer. | |
| 130 DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId()); | |
| 131 | |
| 132 if (stopping_ || !message_loop_) | |
| 133 return; | |
| 134 | |
| 135 stopping_ = true; | |
| 136 message_loop_->PostTask(FROM_HERE, new ThreadQuitTask()); | |
| 137 } | |
| 138 | |
| 139 void Thread::Run(MessageLoop* message_loop) { | |
| 140 message_loop->Run(); | |
| 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 CleanUpAfterMessageLoopDestruction(); | |
| 177 thread_id_ = kInvalidThreadId; | |
| 178 } | |
| 179 | |
| 180 } // namespace base | |
| OLD | NEW |