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