blob: dfeae8162d9b046557ab35029c1c354d1b5063c3 [file] [log] [blame]
Bjorn A Mellemc4f86542019-11-21 10:37:18 -08001/*
2 * Copyright 2019 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#include "test/time_controller/external_time_controller.h"
11
12#include <algorithm>
13#include <map>
14#include <memory>
15#include <utility>
16
17#include "api/task_queue/queued_task.h"
18#include "api/task_queue/task_queue_base.h"
19#include "api/task_queue/task_queue_factory.h"
20#include "api/units/time_delta.h"
21#include "api/units/timestamp.h"
22#include "modules/include/module.h"
23#include "modules/utility/include/process_thread.h"
Sebastian Janssonfc8279d2020-01-16 11:45:59 +010024#include "rtc_base/checks.h"
Bjorn A Mellemc4f86542019-11-21 10:37:18 -080025#include "rtc_base/synchronization/yield_policy.h"
26#include "test/time_controller/simulated_time_controller.h"
27
28namespace webrtc {
29
30// Wraps a ProcessThread so that it can reschedule the time controller whenever
31// an external call changes the ProcessThread's state. For example, when a new
32// module is registered, the ProcessThread may need to be called sooner than the
33// time controller's currently-scheduled deadline.
34class ExternalTimeController::ProcessThreadWrapper : public ProcessThread {
35 public:
36 ProcessThreadWrapper(ExternalTimeController* parent,
37 std::unique_ptr<ProcessThread> thread)
38 : parent_(parent), thread_(std::move(thread)) {}
39
40 void Start() override {
41 parent_->UpdateTime();
42 thread_->Start();
43 parent_->ScheduleNext();
44 }
45
46 void Stop() override {
47 parent_->UpdateTime();
48 thread_->Stop();
49 parent_->ScheduleNext();
50 }
51
52 void WakeUp(Module* module) override {
53 parent_->UpdateTime();
54 thread_->WakeUp(GetWrapper(module));
55 parent_->ScheduleNext();
56 }
57
58 void PostTask(std::unique_ptr<QueuedTask> task) override {
59 parent_->UpdateTime();
60 thread_->PostTask(std::move(task));
61 parent_->ScheduleNext();
62 }
63
64 void RegisterModule(Module* module, const rtc::Location& from) override {
65 parent_->UpdateTime();
66 module_wrappers_.emplace(module, new ModuleWrapper(module, this));
67 thread_->RegisterModule(GetWrapper(module), from);
68 parent_->ScheduleNext();
69 }
70
71 void DeRegisterModule(Module* module) override {
72 parent_->UpdateTime();
73 thread_->DeRegisterModule(GetWrapper(module));
74 parent_->ScheduleNext();
75 module_wrappers_.erase(module);
76 }
77
78 private:
79 class ModuleWrapper : public Module {
80 public:
81 ModuleWrapper(Module* module, ProcessThreadWrapper* thread)
82 : module_(module), thread_(thread) {}
83
84 int64_t TimeUntilNextProcess() override {
85 return module_->TimeUntilNextProcess();
86 }
87
88 void Process() override { module_->Process(); }
89
90 void ProcessThreadAttached(ProcessThread* process_thread) override {
91 if (process_thread) {
92 module_->ProcessThreadAttached(thread_);
93 } else {
94 module_->ProcessThreadAttached(nullptr);
95 }
96 }
97
98 private:
99 Module* module_;
100 ProcessThreadWrapper* thread_;
101 };
102
103 ModuleWrapper* GetWrapper(Module* module) {
104 auto it = module_wrappers_.find(module);
105 RTC_DCHECK(it != module_wrappers_.end());
106 return it->second.get();
107 }
108
109 ExternalTimeController* const parent_;
110 std::unique_ptr<ProcessThread> thread_;
111 std::map<Module*, std::unique_ptr<ModuleWrapper>> module_wrappers_;
112};
113
114// Wraps a TaskQueue so that it can reschedule the time controller whenever
115// an external call schedules a new task.
116class ExternalTimeController::TaskQueueWrapper : public TaskQueueBase {
117 public:
118 TaskQueueWrapper(ExternalTimeController* parent,
119 std::unique_ptr<TaskQueueBase, TaskQueueDeleter> base)
120 : parent_(parent), base_(std::move(base)) {}
121
122 void PostTask(std::unique_ptr<QueuedTask> task) override {
123 parent_->UpdateTime();
124 base_->PostTask(std::make_unique<TaskWrapper>(std::move(task), this));
125 parent_->ScheduleNext();
126 }
127
128 void PostDelayedTask(std::unique_ptr<QueuedTask> task, uint32_t ms) override {
129 parent_->UpdateTime();
130 base_->PostDelayedTask(std::make_unique<TaskWrapper>(std::move(task), this),
131 ms);
132 parent_->ScheduleNext();
133 }
134
135 void Delete() override { delete this; }
136
137 private:
138 class TaskWrapper : public QueuedTask {
139 public:
140 TaskWrapper(std::unique_ptr<QueuedTask> task, TaskQueueWrapper* queue)
141 : task_(std::move(task)), queue_(queue) {}
142
143 bool Run() override {
144 CurrentTaskQueueSetter current(queue_);
145 if (!task_->Run()) {
146 task_.release();
147 }
148 // The wrapper should always be deleted, even if it releases the inner
149 // task, in order to avoid leaking wrappers.
150 return true;
151 }
152
153 private:
154 std::unique_ptr<QueuedTask> task_;
155 TaskQueueWrapper* queue_;
156 };
157
158 ExternalTimeController* const parent_;
159 std::unique_ptr<TaskQueueBase, TaskQueueDeleter> base_;
160};
161
162ExternalTimeController::ExternalTimeController(ControlledAlarmClock* alarm)
Sebastian Jansson340af972019-12-04 10:07:48 +0100163 : alarm_(alarm),
164 impl_(alarm_->GetClock()->CurrentTime()),
165 yield_policy_(&impl_) {
Bjorn A Mellemc4f86542019-11-21 10:37:18 -0800166 global_clock_.SetTime(alarm_->GetClock()->CurrentTime());
167 alarm_->SetCallback([this] { Run(); });
168}
169
170Clock* ExternalTimeController::GetClock() {
171 return alarm_->GetClock();
172}
173
174TaskQueueFactory* ExternalTimeController::GetTaskQueueFactory() {
175 return this;
176}
177
178std::unique_ptr<ProcessThread> ExternalTimeController::CreateProcessThread(
179 const char* thread_name) {
180 return std::make_unique<ProcessThreadWrapper>(
181 this, impl_.CreateProcessThread(thread_name));
182}
183
Markus Handell486cc552019-12-03 14:37:28 +0100184void ExternalTimeController::AdvanceTime(TimeDelta duration) {
Bjorn A Mellemc4f86542019-11-21 10:37:18 -0800185 alarm_->Sleep(duration);
186}
187
Sebastian Janssonfc8279d2020-01-16 11:45:59 +0100188std::unique_ptr<rtc::Thread> ExternalTimeController::CreateThread(
189 const std::string& name,
190 std::unique_ptr<rtc::SocketServer> socket_server) {
191 RTC_NOTREACHED();
192 return nullptr;
193}
194
195rtc::Thread* ExternalTimeController::GetMainThread() {
196 RTC_NOTREACHED();
197 return nullptr;
198}
199
Bjorn A Mellemc4f86542019-11-21 10:37:18 -0800200std::unique_ptr<TaskQueueBase, TaskQueueDeleter>
201ExternalTimeController::CreateTaskQueue(
202 absl::string_view name,
203 TaskQueueFactory::Priority priority) const {
204 return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(
205 new TaskQueueWrapper(const_cast<ExternalTimeController*>(this),
206 impl_.CreateTaskQueue(name, priority)));
207}
208
209void ExternalTimeController::Run() {
210 rtc::ScopedYieldPolicy yield_policy(&impl_);
211 UpdateTime();
212 impl_.RunReadyRunners();
213 ScheduleNext();
214}
215
216void ExternalTimeController::UpdateTime() {
217 Timestamp now = alarm_->GetClock()->CurrentTime();
218 impl_.AdvanceTime(now);
219 global_clock_.SetTime(now);
220}
221
222void ExternalTimeController::ScheduleNext() {
223 RTC_DCHECK_EQ(impl_.CurrentTime(), alarm_->GetClock()->CurrentTime());
224 TimeDelta delay =
225 std::max(impl_.NextRunTime() - impl_.CurrentTime(), TimeDelta::Zero());
226 if (delay.IsFinite()) {
227 alarm_->ScheduleAlarmAt(alarm_->GetClock()->CurrentTime() + delay);
228 }
229}
230
231} // namespace webrtc