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