LCOV - code coverage report
Current view: directory - ipc/chromium/src/base - thread.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 66 55 83.3 %
Date: 2012-06-02 Functions: 19 15 78.9 %

       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/string_util.h"
       9                 : #include "base/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            7095 : class ThreadQuitTask : public Task {
      16                 :  public:
      17            1419 :   virtual void Run() {
      18            1419 :     MessageLoop::current()->Quit();
      19            1419 :     Thread::SetThreadWasQuitProperly(true);
      20            1419 :   }
      21                 : };
      22                 : 
      23                 : // Used to pass data to ThreadMain.  This structure is allocated on the stack
      24                 : // from within StartWithOptions.
      25            1420 : 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            1420 :   explicit StartupData(const Options& opt)
      33                 :       : options(opt),
      34            1420 :         event(false, false) {}
      35                 : };
      36                 : 
      37            1420 : Thread::Thread(const char *name)
      38                 :     : startup_data_(NULL),
      39                 :       thread_(0),
      40                 :       message_loop_(NULL),
      41                 :       thread_id_(0),
      42            1420 :       name_(name) {
      43            1420 : }
      44                 : 
      45            2838 : Thread::~Thread() {
      46            1419 :   Stop();
      47            2838 : }
      48                 : 
      49                 : namespace {
      50                 : 
      51                 : // We use this thread-local variable to record whether or not a thread exited
      52                 : // because its Stop method was called.  This allows us to catch cases where
      53                 : // MessageLoop::Quit() is called directly, which is unexpected when using a
      54                 : // Thread to setup and run a MessageLoop.
      55                 : base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool(
      56            1464 :     base::LINKER_INITIALIZED);
      57                 : 
      58                 : }  // namespace
      59                 : 
      60            2839 : void Thread::SetThreadWasQuitProperly(bool flag) {
      61            2839 :   lazy_tls_bool.Pointer()->Set(flag);
      62            2839 : }
      63                 : 
      64            1419 : bool Thread::GetThreadWasQuitProperly() {
      65            1419 :   bool quit_properly = true;
      66                 : #ifndef NDEBUG
      67            1419 :   quit_properly = lazy_tls_bool.Pointer()->Get();
      68                 : #endif
      69            1419 :   return quit_properly;
      70                 : }
      71                 : 
      72               0 : bool Thread::Start() {
      73               0 :   return StartWithOptions(Options());
      74                 : }
      75                 : 
      76            1420 : bool Thread::StartWithOptions(const Options& options) {
      77            1420 :   DCHECK(!message_loop_);
      78                 : 
      79            1420 :   SetThreadWasQuitProperly(false);
      80                 : 
      81            2840 :   StartupData startup_data(options);
      82            1420 :   startup_data_ = &startup_data;
      83                 : 
      84            1420 :   if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
      85               0 :     DLOG(ERROR) << "failed to create thread";
      86               0 :     startup_data_ = NULL;  // Record that we failed to start.
      87               0 :     return false;
      88                 :   }
      89                 : 
      90                 :   // Wait for the thread to start and initialize message_loop_
      91            1420 :   startup_data.event.Wait();
      92                 : 
      93            1420 :   DCHECK(message_loop_);
      94            1420 :   return true;
      95                 : }
      96                 : 
      97            2838 : void Thread::Stop() {
      98            2838 :   if (!thread_was_started())
      99            1419 :     return;
     100                 : 
     101                 :   // We should only be called on the same thread that started us.
     102            1419 :   DCHECK_NE(thread_id_, PlatformThread::CurrentId());
     103                 : 
     104                 :   // StopSoon may have already been called.
     105            1419 :   if (message_loop_)
     106            1419 :     message_loop_->PostTask(FROM_HERE, new ThreadQuitTask());
     107                 : 
     108                 :   // Wait for the thread to exit.  It should already have terminated but make
     109                 :   // sure this assumption is valid.
     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            1419 :   PlatformThread::Join(thread_);
     115                 : 
     116                 :   // The thread can't receive messages anymore.
     117            1419 :   message_loop_ = NULL;
     118                 : 
     119                 :   // The thread no longer needs to be joined.
     120            1419 :   startup_data_ = NULL;
     121                 : }
     122                 : 
     123               0 : void Thread::StopSoon() {
     124               0 :   if (!message_loop_)
     125               0 :     return;
     126                 : 
     127                 :   // We should only be called on the same thread that started us.
     128               0 :   DCHECK_NE(thread_id_, PlatformThread::CurrentId());
     129                 : 
     130                 :   // We had better have a message loop at this point!  If we do not, then it
     131                 :   // most likely means that the thread terminated unexpectedly, probably due
     132                 :   // to someone calling Quit() on our message loop directly.
     133               0 :   DCHECK(message_loop_);
     134                 : 
     135               0 :   message_loop_->PostTask(FROM_HERE, new ThreadQuitTask());
     136                 : }
     137                 : 
     138            1420 : void Thread::ThreadMain() {
     139                 :   // The message loop for this thread.
     140            2839 :   MessageLoop message_loop(startup_data_->options.message_loop_type);
     141                 : 
     142                 :   // Complete the initialization of our Thread object.
     143            1420 :   thread_id_ = PlatformThread::CurrentId();
     144            1420 :   PlatformThread::SetName(name_.c_str());
     145            1420 :   message_loop.set_thread_name(name_);
     146            1420 :   message_loop_ = &message_loop;
     147                 : 
     148                 :   // Let the thread do extra initialization.
     149                 :   // Let's do this before signaling we are started.
     150            1420 :   Init();
     151                 : 
     152            1420 :   startup_data_->event.Signal();
     153                 :   // startup_data_ can't be touched anymore since the starting thread is now
     154                 :   // unlocked.
     155                 : 
     156            1420 :   message_loop.Run();
     157                 : 
     158                 :   // Let the thread do extra cleanup.
     159            1419 :   CleanUp();
     160                 : 
     161                 :   // Assert that MessageLoop::Quit was called by ThreadQuitTask.
     162            1419 :   DCHECK(GetThreadWasQuitProperly());
     163                 : 
     164                 :   // We can't receive messages anymore.
     165            1419 :   message_loop_ = NULL;
     166            1419 :   thread_id_ = 0;
     167            1419 : }
     168                 : 
     169            4392 : }  // namespace base

Generated by: LCOV version 1.7