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 "rtc_base/deprecated/signal_thread.h"
12 
13 #include <memory>
14 
15 #include "rtc_base/checks.h"
16 #include "rtc_base/location.h"
17 #include "rtc_base/null_socket_server.h"
18 #include "rtc_base/socket_server.h"
19 
20 namespace rtc {
21 
22 ///////////////////////////////////////////////////////////////////////////////
23 // SignalThread
24 ///////////////////////////////////////////////////////////////////////////////
25 
DEPRECATED_SignalThread()26 DEPRECATED_SignalThread::DEPRECATED_SignalThread()
27     : main_(Thread::Current()), worker_(this), state_(kInit), refcount_(1) {
28   main_->SignalQueueDestroyed.connect(
29       this, &DEPRECATED_SignalThread::OnMainThreadDestroyed);
30   worker_.SetName("SignalThread", this);
31 }
32 
~DEPRECATED_SignalThread()33 DEPRECATED_SignalThread::~DEPRECATED_SignalThread() {
34   rtc::CritScope lock(&cs_);
35   RTC_DCHECK(refcount_ == 0);
36 }
37 
SetName(const std::string & name,const void * obj)38 bool DEPRECATED_SignalThread::SetName(const std::string& name,
39                                       const void* obj) {
40   EnterExit ee(this);
41   RTC_DCHECK(!destroy_called_);
42   RTC_DCHECK(main_->IsCurrent());
43   RTC_DCHECK(kInit == state_);
44   return worker_.SetName(name, obj);
45 }
46 
Start()47 void DEPRECATED_SignalThread::Start() {
48   EnterExit ee(this);
49   RTC_DCHECK(!destroy_called_);
50   RTC_DCHECK(main_->IsCurrent());
51   if (kInit == state_ || kComplete == state_) {
52     state_ = kRunning;
53     OnWorkStart();
54     worker_.Start();
55   } else {
56     RTC_NOTREACHED();
57   }
58 }
59 
Destroy(bool wait)60 void DEPRECATED_SignalThread::Destroy(bool wait) {
61   EnterExit ee(this);
62   // Sometimes the caller can't guarantee which thread will call Destroy, only
63   // that it will be the last thing it does.
64   // RTC_DCHECK(main_->IsCurrent());
65   RTC_DCHECK(!destroy_called_);
66   destroy_called_ = true;
67   if ((kInit == state_) || (kComplete == state_)) {
68     refcount_--;
69   } else if (kRunning == state_ || kReleasing == state_) {
70     state_ = kStopping;
71     // OnWorkStop() must follow Quit(), so that when the thread wakes up due to
72     // OWS(), ContinueWork() will return false.
73     worker_.Quit();
74     OnWorkStop();
75     if (wait) {
76       // Release the thread's lock so that it can return from ::Run.
77       cs_.Leave();
78       worker_.Stop();
79       cs_.Enter();
80       refcount_--;
81     }
82   } else {
83     RTC_NOTREACHED();
84   }
85 }
86 
Release()87 void DEPRECATED_SignalThread::Release() {
88   EnterExit ee(this);
89   RTC_DCHECK(!destroy_called_);
90   RTC_DCHECK(main_->IsCurrent());
91   if (kComplete == state_) {
92     refcount_--;
93   } else if (kRunning == state_) {
94     state_ = kReleasing;
95   } else {
96     // if (kInit == state_) use Destroy()
97     RTC_NOTREACHED();
98   }
99 }
100 
ContinueWork()101 bool DEPRECATED_SignalThread::ContinueWork() {
102   EnterExit ee(this);
103   RTC_DCHECK(!destroy_called_);
104   RTC_DCHECK(worker_.IsCurrent());
105   return worker_.ProcessMessages(0);
106 }
107 
OnMessage(Message * msg)108 void DEPRECATED_SignalThread::OnMessage(Message* msg) {
109   EnterExit ee(this);
110   if (ST_MSG_WORKER_DONE == msg->message_id) {
111     RTC_DCHECK(main_->IsCurrent());
112     OnWorkDone();
113     bool do_delete = false;
114     if (kRunning == state_) {
115       state_ = kComplete;
116     } else {
117       do_delete = true;
118     }
119     if (kStopping != state_) {
120       // Before signaling that the work is done, make sure that the worker
121       // thread actually is done. We got here because DoWork() finished and
122       // Run() posted the ST_MSG_WORKER_DONE message. This means the worker
123       // thread is about to go away anyway, but sometimes it doesn't actually
124       // finish before SignalWorkDone is processed, and for a reusable
125       // SignalThread this makes an assert in thread.cc fire.
126       //
127       // Calling Stop() on the worker ensures that the OS thread that underlies
128       // the worker will finish, and will be set to null, enabling us to call
129       // Start() again.
130       worker_.Stop();
131       SignalWorkDone(this);
132     }
133     if (do_delete) {
134       refcount_--;
135     }
136   }
137 }
138 
Worker(DEPRECATED_SignalThread * parent)139 DEPRECATED_SignalThread::Worker::Worker(DEPRECATED_SignalThread* parent)
140     : Thread(std::make_unique<NullSocketServer>(), /*do_init=*/false),
141       parent_(parent) {
142   DoInit();
143 }
144 
~Worker()145 DEPRECATED_SignalThread::Worker::~Worker() {
146   Stop();
147 }
148 
Run()149 void DEPRECATED_SignalThread::Worker::Run() {
150   parent_->Run();
151 }
152 
Run()153 void DEPRECATED_SignalThread::Run() {
154   DoWork();
155   {
156     EnterExit ee(this);
157     if (main_) {
158       main_->Post(RTC_FROM_HERE, this, ST_MSG_WORKER_DONE);
159     }
160   }
161 }
162 
OnMainThreadDestroyed()163 void DEPRECATED_SignalThread::OnMainThreadDestroyed() {
164   EnterExit ee(this);
165   main_ = nullptr;
166 }
167 
IsProcessingMessagesForTesting()168 bool DEPRECATED_SignalThread::Worker::IsProcessingMessagesForTesting() {
169   return false;
170 }
171 
172 }  // namespace rtc
173