Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/base/signalthread.h"
     12 
     13 #include "webrtc/base/common.h"
     14 
     15 namespace rtc {
     16 
     17 ///////////////////////////////////////////////////////////////////////////////
     18 // SignalThread
     19 ///////////////////////////////////////////////////////////////////////////////
     20 
     21 SignalThread::SignalThread()
     22     : main_(Thread::Current()),
     23       worker_(this),
     24       state_(kInit),
     25       refcount_(1) {
     26   main_->SignalQueueDestroyed.connect(this,
     27                                       &SignalThread::OnMainThreadDestroyed);
     28   worker_.SetName("SignalThread", this);
     29 }
     30 
     31 SignalThread::~SignalThread() {
     32   ASSERT(refcount_ == 0);
     33 }
     34 
     35 bool SignalThread::SetName(const std::string& name, const void* obj) {
     36   EnterExit ee(this);
     37   ASSERT(main_->IsCurrent());
     38   ASSERT(kInit == state_);
     39   return worker_.SetName(name, obj);
     40 }
     41 
     42 void SignalThread::Start() {
     43   EnterExit ee(this);
     44   ASSERT(main_->IsCurrent());
     45   if (kInit == state_ || kComplete == state_) {
     46     state_ = kRunning;
     47     OnWorkStart();
     48     worker_.Start();
     49   } else {
     50     ASSERT(false);
     51   }
     52 }
     53 
     54 void SignalThread::Destroy(bool wait) {
     55   EnterExit ee(this);
     56   ASSERT(main_->IsCurrent());
     57   if ((kInit == state_) || (kComplete == state_)) {
     58     refcount_--;
     59   } else if (kRunning == state_ || kReleasing == state_) {
     60     state_ = kStopping;
     61     // OnWorkStop() must follow Quit(), so that when the thread wakes up due to
     62     // OWS(), ContinueWork() will return false.
     63     worker_.Quit();
     64     OnWorkStop();
     65     if (wait) {
     66       // Release the thread's lock so that it can return from ::Run.
     67       cs_.Leave();
     68       worker_.Stop();
     69       cs_.Enter();
     70       refcount_--;
     71     }
     72   } else {
     73     ASSERT(false);
     74   }
     75 }
     76 
     77 void SignalThread::Release() {
     78   EnterExit ee(this);
     79   ASSERT(main_->IsCurrent());
     80   if (kComplete == state_) {
     81     refcount_--;
     82   } else if (kRunning == state_) {
     83     state_ = kReleasing;
     84   } else {
     85     // if (kInit == state_) use Destroy()
     86     ASSERT(false);
     87   }
     88 }
     89 
     90 bool SignalThread::ContinueWork() {
     91   EnterExit ee(this);
     92   ASSERT(worker_.IsCurrent());
     93   return worker_.ProcessMessages(0);
     94 }
     95 
     96 void SignalThread::OnMessage(Message *msg) {
     97   EnterExit ee(this);
     98   if (ST_MSG_WORKER_DONE == msg->message_id) {
     99     ASSERT(main_->IsCurrent());
    100     OnWorkDone();
    101     bool do_delete = false;
    102     if (kRunning == state_) {
    103       state_ = kComplete;
    104     } else {
    105       do_delete = true;
    106     }
    107     if (kStopping != state_) {
    108       // Before signaling that the work is done, make sure that the worker
    109       // thread actually is done. We got here because DoWork() finished and
    110       // Run() posted the ST_MSG_WORKER_DONE message. This means the worker
    111       // thread is about to go away anyway, but sometimes it doesn't actually
    112       // finish before SignalWorkDone is processed, and for a reusable
    113       // SignalThread this makes an assert in thread.cc fire.
    114       //
    115       // Calling Stop() on the worker ensures that the OS thread that underlies
    116       // the worker will finish, and will be set to NULL, enabling us to call
    117       // Start() again.
    118       worker_.Stop();
    119       SignalWorkDone(this);
    120     }
    121     if (do_delete) {
    122       refcount_--;
    123     }
    124   }
    125 }
    126 
    127 SignalThread::Worker::~Worker() {
    128   Stop();
    129 }
    130 
    131 void SignalThread::Worker::Run() {
    132   parent_->Run();
    133 }
    134 
    135 void SignalThread::Run() {
    136   DoWork();
    137   {
    138     EnterExit ee(this);
    139     if (main_) {
    140       main_->Post(this, ST_MSG_WORKER_DONE);
    141     }
    142   }
    143 }
    144 
    145 void SignalThread::OnMainThreadDestroyed() {
    146   EnterExit ee(this);
    147   main_ = NULL;
    148 }
    149 
    150 }  // namespace rtc
    151