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