• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004--2009, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "talk/base/signalthread.h"
29 
30 #include "talk/base/common.h"
31 
32 namespace talk_base {
33 
34 ///////////////////////////////////////////////////////////////////////////////
35 // SignalThread
36 ///////////////////////////////////////////////////////////////////////////////
37 
SignalThread()38 SignalThread::SignalThread() : main_(Thread::Current()), state_(kInit) {
39   main_->SignalQueueDestroyed.connect(this,
40                                       &SignalThread::OnMainThreadDestroyed);
41   refcount_ = 1;
42   worker_.parent_ = this;
43   worker_.SetName("SignalThread", this);
44 }
45 
~SignalThread()46 SignalThread::~SignalThread() {
47   ASSERT(refcount_ == 0);
48 }
49 
SetName(const std::string & name,const void * obj)50 bool SignalThread::SetName(const std::string& name, const void* obj) {
51   EnterExit ee(this);
52   ASSERT(main_->IsCurrent());
53   ASSERT(kInit == state_);
54   return worker_.SetName(name, obj);
55 }
56 
SetPriority(ThreadPriority priority)57 bool SignalThread::SetPriority(ThreadPriority priority) {
58   EnterExit ee(this);
59   ASSERT(main_->IsCurrent());
60   ASSERT(kInit == state_);
61   return worker_.SetPriority(priority);
62 }
63 
Start()64 void SignalThread::Start() {
65   EnterExit ee(this);
66   ASSERT(main_->IsCurrent());
67   if (kInit == state_ || kComplete == state_) {
68     state_ = kRunning;
69     OnWorkStart();
70     worker_.Start();
71   } else {
72     ASSERT(false);
73   }
74 }
75 
Destroy(bool wait)76 void SignalThread::Destroy(bool wait) {
77   EnterExit ee(this);
78   ASSERT(main_->IsCurrent());
79   if ((kInit == state_) || (kComplete == state_)) {
80     refcount_--;
81   } else if (kRunning == state_ || kReleasing == state_) {
82     state_ = kStopping;
83     // OnWorkStop() must follow Quit(), so that when the thread wakes up due to
84     // OWS(), ContinueWork() will return false.
85     worker_.Quit();
86     OnWorkStop();
87     if (wait) {
88       // Release the thread's lock so that it can return from ::Run.
89       cs_.Leave();
90       worker_.Stop();
91       cs_.Enter();
92       refcount_--;
93     }
94   } else {
95     ASSERT(false);
96   }
97 }
98 
Release()99 void SignalThread::Release() {
100   EnterExit ee(this);
101   ASSERT(main_->IsCurrent());
102   if (kComplete == state_) {
103     refcount_--;
104   } else if (kRunning == state_) {
105     state_ = kReleasing;
106   } else {
107     // if (kInit == state_) use Destroy()
108     ASSERT(false);
109   }
110 }
111 
ContinueWork()112 bool SignalThread::ContinueWork() {
113   EnterExit ee(this);
114   ASSERT(worker_.IsCurrent());
115   return worker_.ProcessMessages(0);
116 }
117 
OnMessage(Message * msg)118 void SignalThread::OnMessage(Message *msg) {
119   EnterExit ee(this);
120   if (ST_MSG_WORKER_DONE == msg->message_id) {
121     ASSERT(main_->IsCurrent());
122     OnWorkDone();
123     bool do_delete = false;
124     if (kRunning == state_) {
125       state_ = kComplete;
126     } else {
127       do_delete = true;
128     }
129     if (kStopping != state_) {
130       // Before signaling that the work is done, make sure that the worker
131       // thread actually is done. We got here because DoWork() finished and
132       // Run() posted the ST_MSG_WORKER_DONE message. This means the worker
133       // thread is about to go away anyway, but sometimes it doesn't actually
134       // finish before SignalWorkDone is processed, and for a reusable
135       // SignalThread this makes an assert in thread.cc fire.
136       //
137       // Calling Stop() on the worker ensures that the OS thread that underlies
138       // the worker will finish, and will be set to NULL, enabling us to call
139       // Start() again.
140       worker_.Stop();
141       SignalWorkDone(this);
142     }
143     if (do_delete) {
144       refcount_--;
145     }
146   }
147 }
148 
Run()149 void SignalThread::Run() {
150   DoWork();
151   {
152     EnterExit ee(this);
153     if (main_) {
154       main_->Post(this, ST_MSG_WORKER_DONE);
155     }
156   }
157 }
158 
OnMainThreadDestroyed()159 void SignalThread::OnMainThreadDestroyed() {
160   EnterExit ee(this);
161   main_ = NULL;
162 }
163 
164 }  // namespace talk_base
165