Home | History | Annotate | Download | only in threading
      1 // Copyright (c) 2012 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/bind.h"
      8 #include "base/lazy_instance.h"
      9 #include "base/location.h"
     10 #include "base/run_loop.h"
     11 #include "base/synchronization/waitable_event.h"
     12 #include "base/threading/thread_id_name_manager.h"
     13 #include "base/threading/thread_local.h"
     14 #include "base/threading/thread_restrictions.h"
     15 #include "build/build_config.h"
     16 
     17 #if defined(OS_WIN)
     18 #include "base/win/scoped_com_initializer.h"
     19 #endif
     20 
     21 namespace base {
     22 
     23 namespace {
     24 
     25 // We use this thread-local variable to record whether or not a thread exited
     26 // because its Stop method was called.  This allows us to catch cases where
     27 // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when
     28 // using a Thread to setup and run a MessageLoop.
     29 base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool =
     30     LAZY_INSTANCE_INITIALIZER;
     31 
     32 }  // namespace
     33 
     34 // This is used to trigger the message loop to exit.
     35 void ThreadQuitHelper() {
     36   MessageLoop::current()->QuitWhenIdle();
     37   Thread::SetThreadWasQuitProperly(true);
     38 }
     39 
     40 Thread::Options::Options()
     41     : message_loop_type(MessageLoop::TYPE_DEFAULT),
     42       timer_slack(TIMER_SLACK_NONE),
     43       stack_size(0),
     44       priority(ThreadPriority::NORMAL) {
     45 }
     46 
     47 Thread::Options::Options(MessageLoop::Type type,
     48                          size_t size)
     49     : message_loop_type(type),
     50       timer_slack(TIMER_SLACK_NONE),
     51       stack_size(size),
     52       priority(ThreadPriority::NORMAL) {
     53 }
     54 
     55 Thread::Options::Options(const Options& other) = default;
     56 
     57 Thread::Options::~Options() {
     58 }
     59 
     60 Thread::Thread(const std::string& name)
     61     :
     62 #if defined(OS_WIN)
     63       com_status_(NONE),
     64 #endif
     65       stopping_(false),
     66       running_(false),
     67       thread_(0),
     68       id_(kInvalidThreadId),
     69       id_event_(WaitableEvent::ResetPolicy::MANUAL,
     70                 WaitableEvent::InitialState::NOT_SIGNALED),
     71       message_loop_(nullptr),
     72       message_loop_timer_slack_(TIMER_SLACK_NONE),
     73       name_(name),
     74       start_event_(WaitableEvent::ResetPolicy::MANUAL,
     75                    WaitableEvent::InitialState::NOT_SIGNALED) {
     76 }
     77 
     78 Thread::~Thread() {
     79   Stop();
     80 }
     81 
     82 bool Thread::Start() {
     83   Options options;
     84 #if defined(OS_WIN)
     85   if (com_status_ == STA)
     86     options.message_loop_type = MessageLoop::TYPE_UI;
     87 #endif
     88   return StartWithOptions(options);
     89 }
     90 
     91 bool Thread::StartWithOptions(const Options& options) {
     92   DCHECK(!message_loop_);
     93 #if defined(OS_WIN)
     94   DCHECK((com_status_ != STA) ||
     95       (options.message_loop_type == MessageLoop::TYPE_UI));
     96 #endif
     97 
     98   // Reset |id_| here to support restarting the thread.
     99   id_event_.Reset();
    100   id_ = kInvalidThreadId;
    101 
    102   SetThreadWasQuitProperly(false);
    103 
    104   MessageLoop::Type type = options.message_loop_type;
    105   if (!options.message_pump_factory.is_null())
    106     type = MessageLoop::TYPE_CUSTOM;
    107 
    108   message_loop_timer_slack_ = options.timer_slack;
    109   std::unique_ptr<MessageLoop> message_loop =
    110       MessageLoop::CreateUnbound(type, options.message_pump_factory);
    111   message_loop_ = message_loop.get();
    112   start_event_.Reset();
    113 
    114   // Hold the thread_lock_ while starting a new thread, so that we can make sure
    115   // that thread_ is populated before the newly created thread accesses it.
    116   {
    117     AutoLock lock(thread_lock_);
    118     if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_,
    119                                             options.priority)) {
    120       DLOG(ERROR) << "failed to create thread";
    121       message_loop_ = nullptr;
    122       return false;
    123     }
    124   }
    125 
    126   // The ownership of message_loop is managemed by the newly created thread
    127   // within the ThreadMain.
    128   ignore_result(message_loop.release());
    129 
    130   DCHECK(message_loop_);
    131   return true;
    132 }
    133 
    134 bool Thread::StartAndWaitForTesting() {
    135   bool result = Start();
    136   if (!result)
    137     return false;
    138   WaitUntilThreadStarted();
    139   return true;
    140 }
    141 
    142 bool Thread::WaitUntilThreadStarted() const {
    143   if (!message_loop_)
    144     return false;
    145   base::ThreadRestrictions::ScopedAllowWait allow_wait;
    146   start_event_.Wait();
    147   return true;
    148 }
    149 
    150 void Thread::Stop() {
    151   AutoLock lock(thread_lock_);
    152   if (thread_.is_null())
    153     return;
    154 
    155   StopSoon();
    156 
    157   // Wait for the thread to exit.
    158   //
    159   // TODO(darin): Unfortunately, we need to keep message_loop_ around until
    160   // the thread exits.  Some consumers are abusing the API.  Make them stop.
    161   //
    162   PlatformThread::Join(thread_);
    163   thread_ = base::PlatformThreadHandle();
    164 
    165   // The thread should nullify message_loop_ on exit.
    166   DCHECK(!message_loop_);
    167 
    168   stopping_ = false;
    169 }
    170 
    171 void Thread::StopSoon() {
    172   // We should only be called on the same thread that started us.
    173 
    174   DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
    175 
    176   if (stopping_ || !message_loop_)
    177     return;
    178 
    179   stopping_ = true;
    180   task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
    181 }
    182 
    183 PlatformThreadId Thread::GetThreadId() const {
    184   // If the thread is created but not started yet, wait for |id_| being ready.
    185   base::ThreadRestrictions::ScopedAllowWait allow_wait;
    186   id_event_.Wait();
    187   return id_;
    188 }
    189 
    190 bool Thread::IsRunning() const {
    191   // If the thread's already started (i.e. message_loop_ is non-null) and
    192   // not yet requested to stop (i.e. stopping_ is false) we can just return
    193   // true. (Note that stopping_ is touched only on the same thread that
    194   // starts / started the new thread so we need no locking here.)
    195   if (message_loop_ && !stopping_)
    196     return true;
    197   // Otherwise check the running_ flag, which is set to true by the new thread
    198   // only while it is inside Run().
    199   AutoLock lock(running_lock_);
    200   return running_;
    201 }
    202 
    203 void Thread::Run(MessageLoop*) {
    204   RunLoop().Run();
    205 }
    206 
    207 void Thread::SetThreadWasQuitProperly(bool flag) {
    208   lazy_tls_bool.Pointer()->Set(flag);
    209 }
    210 
    211 bool Thread::GetThreadWasQuitProperly() {
    212   bool quit_properly = true;
    213 #ifndef NDEBUG
    214   quit_properly = lazy_tls_bool.Pointer()->Get();
    215 #endif
    216   return quit_properly;
    217 }
    218 
    219 void Thread::ThreadMain() {
    220   // First, make GetThreadId() available to avoid deadlocks. It could be called
    221   // any place in the following thread initialization code.
    222   id_ = PlatformThread::CurrentId();
    223   DCHECK_NE(kInvalidThreadId, id_);
    224   id_event_.Signal();
    225 
    226   // Complete the initialization of our Thread object.
    227   PlatformThread::SetName(name_.c_str());
    228 
    229   // Lazily initialize the message_loop so that it can run on this thread.
    230   DCHECK(message_loop_);
    231   std::unique_ptr<MessageLoop> message_loop(message_loop_);
    232   message_loop_->BindToCurrentThread();
    233   message_loop_->SetTimerSlack(message_loop_timer_slack_);
    234 
    235 #if defined(OS_WIN)
    236   std::unique_ptr<win::ScopedCOMInitializer> com_initializer;
    237   if (com_status_ != NONE) {
    238     com_initializer.reset((com_status_ == STA) ?
    239         new win::ScopedCOMInitializer() :
    240         new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
    241   }
    242 #endif
    243 
    244   // Let the thread do extra initialization.
    245   Init();
    246 
    247   {
    248     AutoLock lock(running_lock_);
    249     running_ = true;
    250   }
    251 
    252   start_event_.Signal();
    253 
    254   Run(message_loop_);
    255 
    256   {
    257     AutoLock lock(running_lock_);
    258     running_ = false;
    259   }
    260 
    261   // Let the thread do extra cleanup.
    262   CleanUp();
    263 
    264 #if defined(OS_WIN)
    265   com_initializer.reset();
    266 #endif
    267 
    268   if (message_loop->type() != MessageLoop::TYPE_CUSTOM) {
    269     // Assert that MessageLoop::QuitWhenIdle was called by ThreadQuitHelper.
    270     // Don't check for custom message pumps, because their shutdown might not
    271     // allow this.
    272     DCHECK(GetThreadWasQuitProperly());
    273   }
    274 
    275   // We can't receive messages anymore.
    276   // (The message loop is destructed at the end of this block)
    277   message_loop_ = nullptr;
    278 }
    279 
    280 }  // namespace base
    281