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 bool SignalThread::SetPriority(ThreadPriority priority) {
     43   EnterExit ee(this);
     44   ASSERT(main_->IsCurrent());
     45   ASSERT(kInit == state_);
     46   return worker_.SetPriority(priority);
     47 }
     48 
     49 void SignalThread::Start() {
     50   EnterExit ee(this);
     51   ASSERT(main_->IsCurrent());
     52   if (kInit == state_ || kComplete == state_) {
     53     state_ = kRunning;
     54     OnWorkStart();
     55     worker_.Start();
     56   } else {
     57     ASSERT(false);
     58   }
     59 }
     60 
     61 void SignalThread::Destroy(bool wait) {
     62   EnterExit ee(this);
     63   ASSERT(main_->IsCurrent());
     64   if ((kInit == state_) || (kComplete == state_)) {
     65     refcount_--;
     66   } else if (kRunning == state_ || kReleasing == state_) {
     67     state_ = kStopping;
     68     // OnWorkStop() must follow Quit(), so that when the thread wakes up due to
     69     // OWS(), ContinueWork() will return false.
     70     worker_.Quit();
     71     OnWorkStop();
     72     if (wait) {
     73       // Release the thread's lock so that it can return from ::Run.
     74       cs_.Leave();
     75       worker_.Stop();
     76       cs_.Enter();
     77       refcount_--;
     78     }
     79   } else {
     80     ASSERT(false);
     81   }
     82 }
     83 
     84 void SignalThread::Release() {
     85   EnterExit ee(this);
     86   ASSERT(main_->IsCurrent());
     87   if (kComplete == state_) {
     88     refcount_--;
     89   } else if (kRunning == state_) {
     90     state_ = kReleasing;
     91   } else {
     92     // if (kInit == state_) use Destroy()
     93     ASSERT(false);
     94   }
     95 }
     96 
     97 bool SignalThread::ContinueWork() {
     98   EnterExit ee(this);
     99   ASSERT(worker_.IsCurrent());
    100   return worker_.ProcessMessages(0);
    101 }
    102 
    103 void SignalThread::OnMessage(Message *msg) {
    104   EnterExit ee(this);
    105   if (ST_MSG_WORKER_DONE == msg->message_id) {
    106     ASSERT(main_->IsCurrent());
    107     OnWorkDone();
    108     bool do_delete = false;
    109     if (kRunning == state_) {
    110       state_ = kComplete;
    111     } else {
    112       do_delete = true;
    113     }
    114     if (kStopping != state_) {
    115       // Before signaling that the work is done, make sure that the worker
    116       // thread actually is done. We got here because DoWork() finished and
    117       // Run() posted the ST_MSG_WORKER_DONE message. This means the worker
    118       // thread is about to go away anyway, but sometimes it doesn't actually
    119       // finish before SignalWorkDone is processed, and for a reusable
    120       // SignalThread this makes an assert in thread.cc fire.
    121       //
    122       // Calling Stop() on the worker ensures that the OS thread that underlies
    123       // the worker will finish, and will be set to NULL, enabling us to call
    124       // Start() again.
    125       worker_.Stop();
    126       SignalWorkDone(this);
    127     }
    128     if (do_delete) {
    129       refcount_--;
    130     }
    131   }
    132 }
    133 
    134 void SignalThread::Run() {
    135   DoWork();
    136   {
    137     EnterExit ee(this);
    138     if (main_) {
    139       main_->Post(this, ST_MSG_WORKER_DONE);
    140     }
    141   }
    142 }
    143 
    144 void SignalThread::OnMainThreadDestroyed() {
    145   EnterExit ee(this);
    146   main_ = NULL;
    147 }
    148 
    149 }  // namespace rtc
    150