1 /*
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 "absl/functional/any_invocable.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 "rtc_base/checks.h"
23 #include "rtc_base/synchronization/yield_policy.h"
24 #include "test/time_controller/simulated_time_controller.h"
25
26 namespace webrtc {
27
28 // Wraps a TaskQueue so that it can reschedule the time controller whenever
29 // an external call schedules a new task.
30 class ExternalTimeController::TaskQueueWrapper : public TaskQueueBase {
31 public:
TaskQueueWrapper(ExternalTimeController * parent,std::unique_ptr<TaskQueueBase,TaskQueueDeleter> base)32 TaskQueueWrapper(ExternalTimeController* parent,
33 std::unique_ptr<TaskQueueBase, TaskQueueDeleter> base)
34 : parent_(parent), base_(std::move(base)) {}
35
PostTask(absl::AnyInvocable<void ()&&> task)36 void PostTask(absl::AnyInvocable<void() &&> task) override {
37 parent_->UpdateTime();
38 base_->PostTask(TaskWrapper(std::move(task)));
39 parent_->ScheduleNext();
40 }
41
PostDelayedTask(absl::AnyInvocable<void ()&&> task,TimeDelta delay)42 void PostDelayedTask(absl::AnyInvocable<void() &&> task,
43 TimeDelta delay) override {
44 parent_->UpdateTime();
45 base_->PostDelayedTask(TaskWrapper(std::move(task)), delay);
46 parent_->ScheduleNext();
47 }
48
PostDelayedHighPrecisionTask(absl::AnyInvocable<void ()&&> task,TimeDelta delay)49 void PostDelayedHighPrecisionTask(absl::AnyInvocable<void() &&> task,
50 TimeDelta delay) override {
51 parent_->UpdateTime();
52 base_->PostDelayedHighPrecisionTask(TaskWrapper(std::move(task)), delay);
53 parent_->ScheduleNext();
54 }
55
Delete()56 void Delete() override { delete this; }
57
58 private:
TaskWrapper(absl::AnyInvocable<void ()&&> task)59 absl::AnyInvocable<void() &&> TaskWrapper(
60 absl::AnyInvocable<void() &&> task) {
61 return [task = std::move(task), this]() mutable {
62 CurrentTaskQueueSetter current(this);
63 std::move(task)();
64 };
65 }
66
67 ExternalTimeController* const parent_;
68 std::unique_ptr<TaskQueueBase, TaskQueueDeleter> base_;
69 };
70
ExternalTimeController(ControlledAlarmClock * alarm)71 ExternalTimeController::ExternalTimeController(ControlledAlarmClock* alarm)
72 : alarm_(alarm),
73 impl_(alarm_->GetClock()->CurrentTime()),
74 yield_policy_(&impl_) {
75 global_clock_.SetTime(alarm_->GetClock()->CurrentTime());
76 alarm_->SetCallback([this] { Run(); });
77 }
78
GetClock()79 Clock* ExternalTimeController::GetClock() {
80 return alarm_->GetClock();
81 }
82
GetTaskQueueFactory()83 TaskQueueFactory* ExternalTimeController::GetTaskQueueFactory() {
84 return this;
85 }
86
AdvanceTime(TimeDelta duration)87 void ExternalTimeController::AdvanceTime(TimeDelta duration) {
88 alarm_->Sleep(duration);
89 }
90
CreateThread(const std::string & name,std::unique_ptr<rtc::SocketServer> socket_server)91 std::unique_ptr<rtc::Thread> ExternalTimeController::CreateThread(
92 const std::string& name,
93 std::unique_ptr<rtc::SocketServer> socket_server) {
94 RTC_DCHECK_NOTREACHED();
95 return nullptr;
96 }
97
GetMainThread()98 rtc::Thread* ExternalTimeController::GetMainThread() {
99 RTC_DCHECK_NOTREACHED();
100 return nullptr;
101 }
102
103 std::unique_ptr<TaskQueueBase, TaskQueueDeleter>
CreateTaskQueue(absl::string_view name,TaskQueueFactory::Priority priority) const104 ExternalTimeController::CreateTaskQueue(
105 absl::string_view name,
106 TaskQueueFactory::Priority priority) const {
107 return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(
108 new TaskQueueWrapper(const_cast<ExternalTimeController*>(this),
109 impl_.CreateTaskQueue(name, priority)));
110 }
111
Run()112 void ExternalTimeController::Run() {
113 rtc::ScopedYieldPolicy yield_policy(&impl_);
114 UpdateTime();
115 impl_.RunReadyRunners();
116 ScheduleNext();
117 }
118
UpdateTime()119 void ExternalTimeController::UpdateTime() {
120 Timestamp now = alarm_->GetClock()->CurrentTime();
121 impl_.AdvanceTime(now);
122 global_clock_.SetTime(now);
123 }
124
ScheduleNext()125 void ExternalTimeController::ScheduleNext() {
126 RTC_DCHECK_EQ(impl_.CurrentTime(), alarm_->GetClock()->CurrentTime());
127 TimeDelta delay =
128 std::max(impl_.NextRunTime() - impl_.CurrentTime(), TimeDelta::Zero());
129 if (delay.IsFinite()) {
130 alarm_->ScheduleAlarmAt(alarm_->GetClock()->CurrentTime() + delay);
131 }
132 }
133
134 } // namespace webrtc
135