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