blob: 9b13daa2b96ef04d92bb393432fe2b5d3353ba57 [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_);
91 ModuleCallback cb(module);
92 const auto& found = std::find(modules_.begin(), modules_.end(), cb);
93 DCHECK(found != modules_.end()) << "programmer error?";
94 (*found).next_callback = 0;
95 }
96 wake_up_->Set();
97}
98
99int32_t ProcessThreadImpl::RegisterModule(Module* module) {
100 // Allowed to be called on any thread.
101 {
102 rtc::CritScope lock(&lock_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000103
104 // Only allow module to be registered once.
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000105 ModuleCallback cb(module);
106 if (std::find(modules_.begin(), modules_.end(), cb) != modules_.end())
107 return -1;
108 modules_.push_front(cb);
109 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000110
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000111 // Wake the thread calling ProcessThreadImpl::Process() to update the
112 // waiting time. The waiting time for the just registered module may be
113 // shorter than all other registered modules.
114 wake_up_->Set();
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000115
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000116 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000117}
118
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000119int32_t ProcessThreadImpl::DeRegisterModule(const Module* module) {
120 // Allowed to be called on any thread.
121 rtc::CritScope lock(&lock_);
122 modules_.remove_if([&module](const ModuleCallback& m) {
123 return m.module == module;
124 });
125 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000126}
127
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000128// static
129bool ProcessThreadImpl::Run(void* obj) {
130 return static_cast<ProcessThreadImpl*>(obj)->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +0000131}
132
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000133bool ProcessThreadImpl::Process() {
134 int64_t now = TickTime::MillisecondTimestamp();
135 int64_t next_checkpoint = now + (1000 * 60);
136 {
137 rtc::CritScope lock(&lock_);
138 if (stop_)
139 return false;
140 for (auto& m : modules_) {
141 // TODO(tommi): Would be good to measure the time TimeUntilNextProcess
142 // takes and dcheck if it takes too long (e.g. >=10ms). Ideally this
143 // operation should not require taking a lock, so querying all modules
144 // should run in a matter of nanoseconds.
145 if (m.next_callback == 0)
146 m.next_callback = GetNextCallbackTime(m.module, now);
niklase@google.com470e71d2011-07-07 08:21:25 +0000147
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000148 if (m.next_callback <= now) {
149 m.module->Process();
150 // Use a new 'now' reference to calculate when the next callback
151 // should occur. We'll continue to use 'now' above for the baseline
152 // of calculating how long we should wait, to reduce variance.
153 auto new_now = TickTime::MillisecondTimestamp();
154 m.next_callback = GetNextCallbackTime(m.module, new_now);
155 }
156
157 if (m.next_callback < next_checkpoint)
158 next_checkpoint = m.next_callback;
niklase@google.com470e71d2011-07-07 08:21:25 +0000159 }
tommi@webrtc.org0c3e12b2015-02-06 09:44:12 +0000160 }
161
162 auto time_to_wait = next_checkpoint - TickTime::MillisecondTimestamp();
163 if (time_to_wait > 0)
164 wake_up_->Wait(static_cast<unsigned long>(time_to_wait));
165
166 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000167}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000168} // namespace webrtc