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