• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SetPriority(ThreadPriority priority)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 
Start()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 
Destroy(bool wait)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 
Release()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 
ContinueWork()97 bool SignalThread::ContinueWork() {
98   EnterExit ee(this);
99   ASSERT(worker_.IsCurrent());
100   return worker_.ProcessMessages(0);
101 }
102 
OnMessage(Message * msg)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 
Run()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 
OnMainThreadDestroyed()144 void SignalThread::OnMainThreadDestroyed() {
145   EnterExit ee(this);
146   main_ = NULL;
147 }
148 
149 }  // namespace rtc
150