LCOV - code coverage report
Current view: top level - ipc/chromium/src/base - thread.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 40 80 50.0 %
Date: 2017-07-14 16:53:18 Functions: 8 17 47.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
       4             : // Use of this source code is governed by a BSD-style license that can be
       5             : // found in the LICENSE file.
       6             : 
       7             : #include "base/thread.h"
       8             : 
       9             : #include "base/string_util.h"
      10             : #include "base/thread_local.h"
      11             : #include "base/waitable_event.h"
      12             : #include "GeckoProfiler.h"
      13             : #include "mozilla/IOInterposer.h"
      14             : #include "nsThreadUtils.h"
      15             : 
      16             : #ifdef MOZ_TASK_TRACER
      17             : #include "GeckoTaskTracer.h"
      18             : #endif
      19             : 
      20             : namespace base {
      21             : 
      22             : // This task is used to trigger the message loop to exit.
      23           0 : class ThreadQuitTask : public mozilla::Runnable {
      24             :  public:
      25           0 :   ThreadQuitTask() : mozilla::Runnable("ThreadQuitTask") {}
      26           0 :   NS_IMETHOD Run() override {
      27           0 :     MessageLoop::current()->Quit();
      28           0 :     Thread::SetThreadWasQuitProperly(true);
      29           0 :     return NS_OK;
      30             :   }
      31             : };
      32             : 
      33             : // Used to pass data to ThreadMain.  This structure is allocated on the stack
      34             : // from within StartWithOptions.
      35           8 : struct Thread::StartupData {
      36             :   // We get away with a const reference here because of how we are allocated.
      37             :   const Thread::Options& options;
      38             : 
      39             :   // Used to synchronize thread startup.
      40             :   WaitableEvent event;
      41             : 
      42           8 :   explicit StartupData(const Options& opt)
      43           8 :       : options(opt),
      44           8 :         event(false, false) {}
      45             : };
      46             : 
      47           8 : Thread::Thread(const char *name)
      48             :     : startup_data_(NULL),
      49             :       thread_(0),
      50             :       message_loop_(NULL),
      51             :       thread_id_(0),
      52           8 :       name_(name) {
      53           8 :   MOZ_COUNT_CTOR(base::Thread);
      54           8 : }
      55             : 
      56           0 : Thread::~Thread() {
      57           0 :   MOZ_COUNT_DTOR(base::Thread);
      58           0 :   Stop();
      59           0 : }
      60             : 
      61             : namespace {
      62             : 
      63             : // We use this thread-local variable to record whether or not a thread exited
      64             : // because its Stop method was called.  This allows us to catch cases where
      65             : // MessageLoop::Quit() is called directly, which is unexpected when using a
      66             : // Thread to setup and run a MessageLoop.
      67             : 
      68           8 : static base::ThreadLocalBoolean& get_tls_bool() {
      69           8 :   static base::ThreadLocalBoolean tls_ptr;
      70           8 :   return tls_ptr;
      71             : }
      72             : 
      73             : }  // namespace
      74             : 
      75           8 : void Thread::SetThreadWasQuitProperly(bool flag) {
      76           8 :   get_tls_bool().Set(flag);
      77           8 : }
      78             : 
      79           0 : bool Thread::GetThreadWasQuitProperly() {
      80           0 :   bool quit_properly = true;
      81             : #ifndef NDEBUG
      82           0 :   quit_properly = get_tls_bool().Get();
      83             : #endif
      84           0 :   return quit_properly;
      85             : }
      86             : 
      87           4 : bool Thread::Start() {
      88           4 :   return StartWithOptions(Options());
      89             : }
      90             : 
      91           8 : bool Thread::StartWithOptions(const Options& options) {
      92           8 :   DCHECK(!message_loop_);
      93             : 
      94           8 :   SetThreadWasQuitProperly(false);
      95             : 
      96          16 :   StartupData startup_data(options);
      97           8 :   startup_data_ = &startup_data;
      98             : 
      99           8 :   if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
     100           0 :     DLOG(ERROR) << "failed to create thread";
     101           0 :     startup_data_ = NULL;  // Record that we failed to start.
     102           0 :     return false;
     103             :   }
     104             : 
     105             :   // Wait for the thread to start and initialize message_loop_
     106           8 :   startup_data.event.Wait();
     107             : 
     108           8 :   DCHECK(message_loop_);
     109           8 :   return true;
     110             : }
     111             : 
     112           0 : void Thread::Stop() {
     113           0 :   if (!thread_was_started())
     114           0 :     return;
     115             : 
     116             :   // We should only be called on the same thread that started us.
     117           0 :   DCHECK_NE(thread_id_, PlatformThread::CurrentId());
     118             : 
     119             :   // StopSoon may have already been called.
     120           0 :   if (message_loop_) {
     121           0 :     RefPtr<ThreadQuitTask> task = new ThreadQuitTask();
     122           0 :     message_loop_->PostTask(task.forget());
     123             :   }
     124             : 
     125             :   // Wait for the thread to exit.  It should already have terminated but make
     126             :   // sure this assumption is valid.
     127             :   //
     128             :   // TODO(darin): Unfortunately, we need to keep message_loop_ around until
     129             :   // the thread exits.  Some consumers are abusing the API.  Make them stop.
     130             :   //
     131           0 :   PlatformThread::Join(thread_);
     132             : 
     133             :   // The thread can't receive messages anymore.
     134           0 :   message_loop_ = NULL;
     135             : 
     136             :   // The thread no longer needs to be joined.
     137           0 :   startup_data_ = NULL;
     138             : }
     139             : 
     140           0 : void Thread::StopSoon() {
     141           0 :   if (!message_loop_)
     142           0 :     return;
     143             : 
     144             :   // We should only be called on the same thread that started us.
     145           0 :   DCHECK_NE(thread_id_, PlatformThread::CurrentId());
     146             : 
     147             :   // We had better have a message loop at this point!  If we do not, then it
     148             :   // most likely means that the thread terminated unexpectedly, probably due
     149             :   // to someone calling Quit() on our message loop directly.
     150           0 :   DCHECK(message_loop_);
     151             : 
     152           0 :   RefPtr<ThreadQuitTask> task = new ThreadQuitTask();
     153           0 :   message_loop_->PostTask(task.forget());
     154             : }
     155             : 
     156           8 : void Thread::ThreadMain() {
     157           8 :   mozilla::AutoProfilerRegisterThread registerThread(name_.c_str());
     158           8 :   mozilla::IOInterposer::RegisterCurrentThread();
     159             : 
     160             :   // The message loop for this thread.
     161           8 :   MessageLoop message_loop(startup_data_->options.message_loop_type,
     162          16 :                            NS_GetCurrentThread());
     163             : 
     164             :   // Complete the initialization of our Thread object.
     165           8 :   thread_id_ = PlatformThread::CurrentId();
     166           8 :   PlatformThread::SetName(name_.c_str());
     167           8 :   NS_SetCurrentThreadName(name_.c_str());
     168           8 :   message_loop.set_thread_name(name_);
     169           8 :   message_loop.set_hang_timeouts(startup_data_->options.transient_hang_timeout,
     170          16 :                                  startup_data_->options.permanent_hang_timeout);
     171           8 :   message_loop_ = &message_loop;
     172             : 
     173             :   // Let the thread do extra initialization.
     174             :   // Let's do this before signaling we are started.
     175           8 :   Init();
     176             : 
     177           8 :   startup_data_->event.Signal();
     178             :   // startup_data_ can't be touched anymore since the starting thread is now
     179             :   // unlocked.
     180             : 
     181           8 :   message_loop.Run();
     182             : 
     183             :   // Let the thread do extra cleanup.
     184           0 :   CleanUp();
     185             : 
     186             :   // Assert that MessageLoop::Quit was called by ThreadQuitTask.
     187           0 :   DCHECK(GetThreadWasQuitProperly());
     188             : 
     189           0 :   mozilla::IOInterposer::UnregisterCurrentThread();
     190             : 
     191             : #ifdef MOZ_TASK_TRACER
     192             :   mozilla::tasktracer::FreeTraceInfo();
     193             : #endif
     194             : 
     195             :   // We can't receive messages anymore.
     196           0 :   message_loop_ = NULL;
     197           0 :   thread_id_ = 0;
     198           0 : }
     199             : 
     200             : }  // namespace base

Generated by: LCOV version 1.13