blob: f59a451bdeb3f4a1090fc8d8f58c1d735af6b450 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
xians@webrtc.org6bde7a82012-02-20 08:39:25 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.org8b062002013-07-12 08:28:10 +000011#include "webrtc/modules/utility/source/process_thread_impl.h"
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +000012
Henrik Kjellanderdca1e092017-07-01 16:42:22 +020013#include "webrtc/base/checks.h"
14#include "webrtc/base/task_queue.h"
15#include "webrtc/base/timeutils.h"
16#include "webrtc/base/trace_event.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010017#include "webrtc/modules/include/module.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000018
19namespace webrtc {
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000020namespace {
tommi@webrtc.org3985f012015-02-27 13:36:34 +000021
22// We use this constant internally to signal that a module has requested
23// a callback right away. When this is set, no call to TimeUntilNextProcess
24// should be made, but Process() should be called directly.
25const int64_t kCallProcessImmediately = -1;
26
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000027int64_t GetNextCallbackTime(Module* module, int64_t time_now) {
28 int64_t interval = module->TimeUntilNextProcess();
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000029 if (interval < 0) {
pbos9e260f12015-08-20 01:23:48 -070030 // Falling behind, we should call the callback now.
31 return time_now;
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000032 }
33 return time_now + interval;
34}
niklase@google.com470e71d2011-07-07 08:21:25 +000035}
36
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000037ProcessThread::~ProcessThread() {}
niklase@google.com470e71d2011-07-07 08:21:25 +000038
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000039// static
kwiberg84be5112016-04-27 01:19:58 -070040std::unique_ptr<ProcessThread> ProcessThread::Create(
stefan847855b2015-09-11 09:52:15 -070041 const char* thread_name) {
kwiberg84be5112016-04-27 01:19:58 -070042 return std::unique_ptr<ProcessThread>(new ProcessThreadImpl(thread_name));
niklase@google.com470e71d2011-07-07 08:21:25 +000043}
44
stefan847855b2015-09-11 09:52:15 -070045ProcessThreadImpl::ProcessThreadImpl(const char* thread_name)
46 : wake_up_(EventWrapper::Create()),
47 stop_(false),
48 thread_name_(thread_name) {}
niklase@google.com470e71d2011-07-07 08:21:25 +000049
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000050ProcessThreadImpl::~ProcessThreadImpl() {
henrikg91d6ede2015-09-17 00:24:34 -070051 RTC_DCHECK(thread_checker_.CalledOnValidThread());
52 RTC_DCHECK(!thread_.get());
53 RTC_DCHECK(!stop_);
tommi@webrtc.org03054482015-03-05 13:13:42 +000054
55 while (!queue_.empty()) {
56 delete queue_.front();
57 queue_.pop();
58 }
niklase@google.com470e71d2011-07-07 08:21:25 +000059}
60
tommi@webrtc.org3985f012015-02-27 13:36:34 +000061void ProcessThreadImpl::Start() {
henrikg91d6ede2015-09-17 00:24:34 -070062 RTC_DCHECK(thread_checker_.CalledOnValidThread());
63 RTC_DCHECK(!thread_.get());
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000064 if (thread_.get())
tommi@webrtc.org3985f012015-02-27 13:36:34 +000065 return;
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000066
henrikg91d6ede2015-09-17 00:24:34 -070067 RTC_DCHECK(!stop_);
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000068
tommi0a2391f2017-03-21 02:31:51 -070069 for (ModuleCallback& m : modules_)
70 m.module->ProcessThreadAttached(this);
tommi@webrtc.org3985f012015-02-27 13:36:34 +000071
Peter Boström8c38e8b2015-11-26 17:45:47 +010072 thread_.reset(
73 new rtc::PlatformThread(&ProcessThreadImpl::Run, this, thread_name_));
74 thread_->Start();
niklase@google.com470e71d2011-07-07 08:21:25 +000075}
76
tommi@webrtc.org3985f012015-02-27 13:36:34 +000077void ProcessThreadImpl::Stop() {
henrikg91d6ede2015-09-17 00:24:34 -070078 RTC_DCHECK(thread_checker_.CalledOnValidThread());
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000079 if(!thread_.get())
tommi@webrtc.org3985f012015-02-27 13:36:34 +000080 return;
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000081
82 {
83 rtc::CritScope lock(&lock_);
84 stop_ = true;
85 }
86
87 wake_up_->Set();
88
Peter Boström8c38e8b2015-11-26 17:45:47 +010089 thread_->Stop();
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000090 stop_ = false;
91
Tommi7f375f02015-04-02 14:50:21 +000092 thread_.reset();
tommi@webrtc.org3985f012015-02-27 13:36:34 +000093 for (ModuleCallback& m : modules_)
94 m.module->ProcessThreadAttached(nullptr);
niklase@google.com470e71d2011-07-07 08:21:25 +000095}
96
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000097void ProcessThreadImpl::WakeUp(Module* module) {
98 // Allowed to be called on any thread.
99 {
100 rtc::CritScope lock(&lock_);
tommi@webrtc.org103f3282015-02-08 00:48:10 +0000101 for (ModuleCallback& m : modules_) {
102 if (m.module == module)
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000103 m.next_callback = kCallProcessImmediately;
tommi@webrtc.org103f3282015-02-08 00:48:10 +0000104 }
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000105 }
106 wake_up_->Set();
107}
108
tommi435f98b2016-05-28 14:57:15 -0700109void ProcessThreadImpl::PostTask(std::unique_ptr<rtc::QueuedTask> task) {
tommi@webrtc.org03054482015-03-05 13:13:42 +0000110 // Allowed to be called on any thread.
111 {
112 rtc::CritScope lock(&lock_);
113 queue_.push(task.release());
114 }
115 wake_up_->Set();
116}
117
tommidea489f2017-03-03 03:20:24 -0800118void ProcessThreadImpl::RegisterModule(Module* module,
119 const rtc::Location& from) {
henrikg91d6ede2015-09-17 00:24:34 -0700120 RTC_DCHECK(thread_checker_.CalledOnValidThread());
121 RTC_DCHECK(module);
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000122
kwiberg5377bc72016-10-04 13:46:56 -0700123#if RTC_DCHECK_IS_ON
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000124 {
125 // Catch programmer error.
126 rtc::CritScope lock(&lock_);
127 for (const ModuleCallback& mc : modules_)
henrikg91d6ede2015-09-17 00:24:34 -0700128 RTC_DCHECK(mc.module != module);
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000129 }
130#endif
131
132 // Now that we know the module isn't in the list, we'll call out to notify
133 // the module that it's attached to the worker thread. We don't hold
134 // the lock while we make this call.
135 if (thread_.get())
136 module->ProcessThreadAttached(this);
137
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000138 {
139 rtc::CritScope lock(&lock_);
tommidea489f2017-03-03 03:20:24 -0800140 modules_.push_back(ModuleCallback(module, from));
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000141 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000142
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000143 // Wake the thread calling ProcessThreadImpl::Process() to update the
144 // waiting time. The waiting time for the just registered module may be
145 // shorter than all other registered modules.
146 wake_up_->Set();
niklase@google.com470e71d2011-07-07 08:21:25 +0000147}
148
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000149void ProcessThreadImpl::DeRegisterModule(Module* module) {
tommi0a2391f2017-03-21 02:31:51 -0700150 RTC_DCHECK(thread_checker_.CalledOnValidThread());
henrikg91d6ede2015-09-17 00:24:34 -0700151 RTC_DCHECK(module);
Tommi7f375f02015-04-02 14:50:21 +0000152
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000153 {
154 rtc::CritScope lock(&lock_);
155 modules_.remove_if([&module](const ModuleCallback& m) {
156 return m.module == module;
157 });
Tommi7f375f02015-04-02 14:50:21 +0000158 }
tommi0a2391f2017-03-21 02:31:51 -0700159
160 // Notify the module that it's been detached.
161 module->ProcessThreadAttached(nullptr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000162}
163
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000164// static
165bool ProcessThreadImpl::Run(void* obj) {
166 return static_cast<ProcessThreadImpl*>(obj)->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +0000167}
168
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000169bool ProcessThreadImpl::Process() {
tommidea489f2017-03-03 03:20:24 -0800170 TRACE_EVENT1("webrtc", "ProcessThreadImpl", "name", thread_name_);
Niels Möllerd28db7f2016-05-10 16:31:47 +0200171 int64_t now = rtc::TimeMillis();
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000172 int64_t next_checkpoint = now + (1000 * 60);
tommi@webrtc.org03054482015-03-05 13:13:42 +0000173
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000174 {
175 rtc::CritScope lock(&lock_);
176 if (stop_)
177 return false;
tommi@webrtc.org103f3282015-02-08 00:48:10 +0000178 for (ModuleCallback& m : modules_) {
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000179 // TODO(tommi): Would be good to measure the time TimeUntilNextProcess
180 // takes and dcheck if it takes too long (e.g. >=10ms). Ideally this
181 // operation should not require taking a lock, so querying all modules
182 // should run in a matter of nanoseconds.
183 if (m.next_callback == 0)
184 m.next_callback = GetNextCallbackTime(m.module, now);
niklase@google.com470e71d2011-07-07 08:21:25 +0000185
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000186 if (m.next_callback <= now ||
187 m.next_callback == kCallProcessImmediately) {
tommidea489f2017-03-03 03:20:24 -0800188 {
189 TRACE_EVENT2("webrtc", "ModuleProcess", "function",
190 m.location.function_name(), "file",
191 m.location.file_and_line());
192 m.module->Process();
193 }
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000194 // Use a new 'now' reference to calculate when the next callback
195 // should occur. We'll continue to use 'now' above for the baseline
196 // of calculating how long we should wait, to reduce variance.
Niels Möllerd28db7f2016-05-10 16:31:47 +0200197 int64_t new_now = rtc::TimeMillis();
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000198 m.next_callback = GetNextCallbackTime(m.module, new_now);
199 }
200
201 if (m.next_callback < next_checkpoint)
202 next_checkpoint = m.next_callback;
niklase@google.com470e71d2011-07-07 08:21:25 +0000203 }
tommi@webrtc.org03054482015-03-05 13:13:42 +0000204
205 while (!queue_.empty()) {
tommi435f98b2016-05-28 14:57:15 -0700206 rtc::QueuedTask* task = queue_.front();
tommi@webrtc.org03054482015-03-05 13:13:42 +0000207 queue_.pop();
208 lock_.Leave();
209 task->Run();
210 delete task;
211 lock_.Enter();
212 }
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000213 }
214
Niels Möllerd28db7f2016-05-10 16:31:47 +0200215 int64_t time_to_wait = next_checkpoint - rtc::TimeMillis();
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000216 if (time_to_wait > 0)
217 wake_up_->Wait(static_cast<unsigned long>(time_to_wait));
218
219 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000220}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000221} // namespace webrtc