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