blob: 1e498d470c5eb61824b51ab99fe3c4c60f0b88a0 [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
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000013#include "webrtc/base/checks.h"
14#include "webrtc/modules/interface/module.h"
15#include "webrtc/system_wrappers/interface/logging.h"
16#include "webrtc/system_wrappers/interface/tick_util.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000017
18namespace webrtc {
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000019namespace {
20int64_t GetNextCallbackTime(Module* module, int64_t time_now) {
21 int64_t interval = module->TimeUntilNextProcess();
22 // Currently some implementations erroneously return error codes from
23 // TimeUntilNextProcess(). So, as is, we correct that and log an error.
24 if (interval < 0) {
25 LOG(LS_ERROR) << "TimeUntilNextProcess returned an invalid value "
26 << interval;
27 interval = 0;
28 }
29 return time_now + interval;
30}
niklase@google.com470e71d2011-07-07 08:21:25 +000031}
32
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000033ProcessThread::~ProcessThread() {}
niklase@google.com470e71d2011-07-07 08:21:25 +000034
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000035// static
36rtc::scoped_ptr<ProcessThread> ProcessThread::Create() {
37 return rtc::scoped_ptr<ProcessThread>(new ProcessThreadImpl()).Pass();
niklase@google.com470e71d2011-07-07 08:21:25 +000038}
39
40ProcessThreadImpl::ProcessThreadImpl()
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000041 : wake_up_(EventWrapper::Create()), stop_(false) {
niklase@google.com470e71d2011-07-07 08:21:25 +000042}
43
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000044ProcessThreadImpl::~ProcessThreadImpl() {
45 DCHECK(thread_checker_.CalledOnValidThread());
46 DCHECK(!thread_.get());
47 DCHECK(!stop_);
niklase@google.com470e71d2011-07-07 08:21:25 +000048}
49
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000050int32_t ProcessThreadImpl::Start() {
51 DCHECK(thread_checker_.CalledOnValidThread());
52 if (thread_.get())
niklase@google.com470e71d2011-07-07 08:21:25 +000053 return -1;
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000054
55 DCHECK(!stop_);
56
57 thread_.reset(ThreadWrapper::CreateThread(
58 &ProcessThreadImpl::Run, this, kNormalPriority, "ProcessThread"));
59 unsigned int id;
60 if (!thread_->Start(id)) {
61 thread_.reset();
62 return -1;
63 }
64
65 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000066}
67
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000068int32_t ProcessThreadImpl::Stop() {
69 DCHECK(thread_checker_.CalledOnValidThread());
70 if(!thread_.get())
niklase@google.com470e71d2011-07-07 08:21:25 +000071 return 0;
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000072
73 {
74 rtc::CritScope lock(&lock_);
75 stop_ = true;
76 }
77
78 wake_up_->Set();
79
80 thread_->Stop();
81 thread_.reset();
82 stop_ = false;
83
84 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000085}
86
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000087void ProcessThreadImpl::WakeUp(Module* module) {
88 // Allowed to be called on any thread.
89 {
90 rtc::CritScope lock(&lock_);
tommi@webrtc.org103f3282015-02-08 00:48:10 +000091 for (ModuleCallback& m : modules_) {
92 if (m.module == module)
93 m.next_callback = 0;
94 }
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +000095 }
96 wake_up_->Set();
97}
98
99int32_t ProcessThreadImpl::RegisterModule(Module* module) {
100 // Allowed to be called on any thread.
tommi@webrtc.org103f3282015-02-08 00:48:10 +0000101 DCHECK(module);
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000102 {
103 rtc::CritScope lock(&lock_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000104 // Only allow module to be registered once.
tommi@webrtc.org103f3282015-02-08 00:48:10 +0000105 for (const ModuleCallback& mc : modules_) {
106 if (mc.module == module)
107 return -1;
108 }
109
110 modules_.push_back(ModuleCallback(module));
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000111 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000112
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000113 // Wake the thread calling ProcessThreadImpl::Process() to update the
114 // waiting time. The waiting time for the just registered module may be
115 // shorter than all other registered modules.
116 wake_up_->Set();
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000117
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000118 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000119}
120
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000121int32_t ProcessThreadImpl::DeRegisterModule(const Module* module) {
122 // Allowed to be called on any thread.
tommi@webrtc.org103f3282015-02-08 00:48:10 +0000123 DCHECK(module);
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000124 rtc::CritScope lock(&lock_);
125 modules_.remove_if([&module](const ModuleCallback& m) {
126 return m.module == module;
127 });
128 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000129}
130
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000131// static
132bool ProcessThreadImpl::Run(void* obj) {
133 return static_cast<ProcessThreadImpl*>(obj)->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +0000134}
135
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000136bool ProcessThreadImpl::Process() {
137 int64_t now = TickTime::MillisecondTimestamp();
138 int64_t next_checkpoint = now + (1000 * 60);
139 {
140 rtc::CritScope lock(&lock_);
141 if (stop_)
142 return false;
tommi@webrtc.org103f3282015-02-08 00:48:10 +0000143 for (ModuleCallback& m : modules_) {
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000144 // TODO(tommi): Would be good to measure the time TimeUntilNextProcess
145 // takes and dcheck if it takes too long (e.g. >=10ms). Ideally this
146 // operation should not require taking a lock, so querying all modules
147 // should run in a matter of nanoseconds.
148 if (m.next_callback == 0)
149 m.next_callback = GetNextCallbackTime(m.module, now);
niklase@google.com470e71d2011-07-07 08:21:25 +0000150
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000151 if (m.next_callback <= now) {
152 m.module->Process();
153 // Use a new 'now' reference to calculate when the next callback
154 // should occur. We'll continue to use 'now' above for the baseline
155 // of calculating how long we should wait, to reduce variance.
tommi@webrtc.org103f3282015-02-08 00:48:10 +0000156 int64_t new_now = TickTime::MillisecondTimestamp();
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000157 m.next_callback = GetNextCallbackTime(m.module, new_now);
158 }
159
160 if (m.next_callback < next_checkpoint)
161 next_checkpoint = m.next_callback;
niklase@google.com470e71d2011-07-07 08:21:25 +0000162 }
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000163 }
164
tommi@webrtc.org103f3282015-02-08 00:48:10 +0000165 int64_t time_to_wait = next_checkpoint - TickTime::MillisecondTimestamp();
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000166 if (time_to_wait > 0)
167 wake_up_->Wait(static_cast<unsigned long>(time_to_wait));
168
169 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000170}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000171} // namespace webrtc