blob: 48a677e378dc9e7ab3aebec40e87b19290cae8a8 [file] [log] [blame]
deadbeef8290ddf2017-07-11 16:56:05 -07001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_base/signalthread.h"
deadbeef8290ddf2017-07-11 16:56:05 -070012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "rtc_base/checks.h"
Taylor Brandstetter08672602018-03-02 15:20:33 -080014#include "rtc_base/ptr_util.h"
deadbeef8290ddf2017-07-11 16:56:05 -070015
16namespace rtc {
17
18///////////////////////////////////////////////////////////////////////////////
19// SignalThread
20///////////////////////////////////////////////////////////////////////////////
21
Niels Möller77d37112018-01-15 12:59:43 +010022SignalThread::SignalThread()
deadbeef8290ddf2017-07-11 16:56:05 -070023 : main_(Thread::Current()),
Niels Möller77d37112018-01-15 12:59:43 +010024 worker_(this),
deadbeef8290ddf2017-07-11 16:56:05 -070025 state_(kInit),
26 refcount_(1) {
27 main_->SignalQueueDestroyed.connect(this,
28 &SignalThread::OnMainThreadDestroyed);
29 worker_.SetName("SignalThread", this);
30}
31
32SignalThread::~SignalThread() {
33 RTC_DCHECK(refcount_ == 0);
34}
35
36bool SignalThread::SetName(const std::string& name, const void* obj) {
37 EnterExit ee(this);
38 RTC_DCHECK(main_->IsCurrent());
39 RTC_DCHECK(kInit == state_);
40 return worker_.SetName(name, obj);
41}
42
43void SignalThread::Start() {
44 EnterExit ee(this);
45 RTC_DCHECK(main_->IsCurrent());
46 if (kInit == state_ || kComplete == state_) {
47 state_ = kRunning;
48 OnWorkStart();
49 worker_.Start();
50 } else {
51 RTC_NOTREACHED();
52 }
53}
54
55void SignalThread::Destroy(bool wait) {
56 EnterExit ee(this);
57 RTC_DCHECK(main_->IsCurrent());
58 if ((kInit == state_) || (kComplete == state_)) {
59 refcount_--;
60 } else if (kRunning == state_ || kReleasing == state_) {
61 state_ = kStopping;
62 // OnWorkStop() must follow Quit(), so that when the thread wakes up due to
63 // OWS(), ContinueWork() will return false.
64 worker_.Quit();
65 OnWorkStop();
66 if (wait) {
67 // Release the thread's lock so that it can return from ::Run.
68 cs_.Leave();
69 worker_.Stop();
70 cs_.Enter();
71 refcount_--;
72 }
73 } else {
74 RTC_NOTREACHED();
75 }
76}
77
78void SignalThread::Release() {
79 EnterExit ee(this);
80 RTC_DCHECK(main_->IsCurrent());
81 if (kComplete == state_) {
82 refcount_--;
83 } else if (kRunning == state_) {
84 state_ = kReleasing;
85 } else {
86 // if (kInit == state_) use Destroy()
87 RTC_NOTREACHED();
88 }
89}
90
91bool SignalThread::ContinueWork() {
92 EnterExit ee(this);
93 RTC_DCHECK(worker_.IsCurrent());
94 return worker_.ProcessMessages(0);
95}
96
97void SignalThread::OnMessage(Message *msg) {
98 EnterExit ee(this);
99 if (ST_MSG_WORKER_DONE == msg->message_id) {
100 RTC_DCHECK(main_->IsCurrent());
101 OnWorkDone();
102 bool do_delete = false;
103 if (kRunning == state_) {
104 state_ = kComplete;
105 } else {
106 do_delete = true;
107 }
108 if (kStopping != state_) {
109 // Before signaling that the work is done, make sure that the worker
110 // thread actually is done. We got here because DoWork() finished and
111 // Run() posted the ST_MSG_WORKER_DONE message. This means the worker
112 // thread is about to go away anyway, but sometimes it doesn't actually
113 // finish before SignalWorkDone is processed, and for a reusable
114 // SignalThread this makes an assert in thread.cc fire.
115 //
116 // Calling Stop() on the worker ensures that the OS thread that underlies
117 // the worker will finish, and will be set to null, enabling us to call
118 // Start() again.
119 worker_.Stop();
120 SignalWorkDone(this);
121 }
122 if (do_delete) {
123 refcount_--;
124 }
125 }
126}
127
Taylor Brandstetter08672602018-03-02 15:20:33 -0800128SignalThread::Worker::Worker(SignalThread* parent)
129 : Thread(MakeUnique<NullSocketServer>(), /*do_init=*/false),
130 parent_(parent) {
131 DoInit();
132}
133
deadbeef8290ddf2017-07-11 16:56:05 -0700134SignalThread::Worker::~Worker() {
135 Stop();
136}
137
138void SignalThread::Worker::Run() {
139 parent_->Run();
140}
141
142void SignalThread::Run() {
143 DoWork();
144 {
145 EnterExit ee(this);
146 if (main_) {
147 main_->Post(RTC_FROM_HERE, this, ST_MSG_WORKER_DONE);
148 }
149 }
150}
151
152void SignalThread::OnMainThreadDestroyed() {
153 EnterExit ee(this);
154 main_ = nullptr;
155}
156
157bool SignalThread::Worker::IsProcessingMessages() {
158 return false;
159}
160
161} // namespace rtc