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 
SignalThread()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 
~SignalThread()31 SignalThread::~SignalThread() {
32   ASSERT(refcount_ == 0);
33 }
34 
SetName(const std::string & name,const void * obj)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 
Start()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 
Destroy(bool wait)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 
Release()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 
ContinueWork()90 bool SignalThread::ContinueWork() {
91   EnterExit ee(this);
92   ASSERT(worker_.IsCurrent());
93   return worker_.ProcessMessages(0);
94 }
95 
OnMessage(Message * msg)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 
~Worker()127 SignalThread::Worker::~Worker() {
128   Stop();
129 }
130 
Run()131 void SignalThread::Worker::Run() {
132   parent_->Run();
133 }
134 
Run()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 
OnMainThreadDestroyed()145 void SignalThread::OnMainThreadDestroyed() {
146   EnterExit ee(this);
147   main_ = NULL;
148 }
149 
150 }  // namespace rtc
151