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