Add TimeController to api/test/ and add a CreateTimeController API.

Creates an abstraction for an "alarm clock" which can schedule
time-controller callbacks and exposes a time controller driven by
an external alarm.

Bug: webrtc:9719
Change-Id: I08c2aa9dba25603043bfba48f55c925716a55bae
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158969
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29879}
This commit is contained in:
Bjorn A Mellem
2019-11-21 10:37:18 -08:00
committed by Commit Bot
parent 3daedb6c88
commit c4f865413a
19 changed files with 705 additions and 9 deletions

View File

@ -946,6 +946,45 @@ if (rtc_include_tests) {
]
}
rtc_library("time_controller") {
visibility = [ "*" ]
testonly = true
sources = [
"test/time_controller.h",
]
deps = [
"../modules:module_api",
"../modules/utility:utility",
"../rtc_base",
"../rtc_base:rtc_base_tests_utils",
"../rtc_base:rtc_event",
"../rtc_base/synchronization:sequence_checker",
"../rtc_base/synchronization:yield_policy",
"../rtc_base/task_utils:to_queued_task",
"../system_wrappers",
"task_queue",
"task_queue:default_task_queue_factory",
"units:time_delta",
"units:timestamp",
"//third_party/abseil-cpp/absl/strings",
]
}
rtc_library("create_time_controller") {
visibility = [ "*" ]
testonly = true
sources = [
"test/create_time_controller.cc",
"test/create_time_controller.h",
]
deps = [
":time_controller",
"../test/time_controller",
]
}
rtc_library("rtc_api_unittests") {
testonly = true
@ -958,11 +997,13 @@ if (rtc_include_tests) {
"rtp_packet_infos_unittest.cc",
"rtp_parameters_unittest.cc",
"scoped_refptr_unittest.cc",
"test/create_time_controller_unittest.cc",
"test/loopback_media_transport_unittest.cc",
]
deps = [
":array_view",
":create_time_controller",
":function_view",
":libjingle_peerconnection_api",
":loopback_media_transport",
@ -971,12 +1012,17 @@ if (rtc_include_tests) {
":rtp_packet_info",
":rtp_parameters",
":scoped_refptr",
":time_controller",
"../rtc_base:checks",
"../rtc_base:gunit_helpers",
"../rtc_base:rtc_base_approved",
"../rtc_base:rtc_task_queue",
"../rtc_base/task_utils:repeating_task",
"../test:fileutils",
"../test:test_support",
"task_queue:task_queue_default_factory_unittests",
"units:time_delta",
"units:timestamp",
"units:units_unittests",
"video:video_unittests",
]

View File

@ -32,4 +32,9 @@ specific_include_rules = {
"+rtc_base/thread.h",
"+media/base/media_constants.h",
],
"time_controller\.h": [
"+modules/utility/include/process_thread.h",
"+rtc_base/synchronization/yield_policy.h",
"+system_wrappers/include/clock.h",
],
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/test/create_time_controller.h"
#include <memory>
#include "test/time_controller/external_time_controller.h"
namespace webrtc {
std::unique_ptr<TimeController> CreateTimeController(
ControlledAlarmClock* alarm) {
return std::make_unique<ExternalTimeController>(alarm);
}
} // namespace webrtc

View File

@ -0,0 +1,24 @@
/*
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_TEST_CREATE_TIME_CONTROLLER_H_
#define API_TEST_CREATE_TIME_CONTROLLER_H_
#include <memory>
#include "api/test/time_controller.h"
namespace webrtc {
std::unique_ptr<TimeController> CreateTimeController(
ControlledAlarmClock* alarm);
} // namespace webrtc
#endif // API_TEST_CREATE_TIME_CONTROLLER_H_

View File

@ -0,0 +1,76 @@
/*
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/test/create_time_controller.h"
#include "api/test/time_controller.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
class FakeAlarm : public ControlledAlarmClock {
public:
explicit FakeAlarm(Timestamp start_time);
Clock* GetClock() override;
bool ScheduleAlarmAt(Timestamp deadline) override;
void SetCallback(std::function<void()> callback) override;
void Sleep(TimeDelta duration) override;
private:
SimulatedClock clock_;
Timestamp deadline_;
std::function<void()> callback_;
};
FakeAlarm::FakeAlarm(Timestamp start_time)
: clock_(start_time),
deadline_(Timestamp::PlusInfinity()),
callback_([] {}) {}
Clock* FakeAlarm::GetClock() {
return &clock_;
}
bool FakeAlarm::ScheduleAlarmAt(Timestamp deadline) {
if (deadline < deadline_) {
deadline_ = deadline;
return true;
}
return false;
}
void FakeAlarm::SetCallback(std::function<void()> callback) {
callback_ = callback;
}
void FakeAlarm::Sleep(TimeDelta duration) {
Timestamp end_time = clock_.CurrentTime() + duration;
while (deadline_ <= end_time) {
clock_.AdvanceTime(deadline_ - clock_.CurrentTime());
deadline_ = Timestamp::PlusInfinity();
callback_();
}
clock_.AdvanceTime(end_time - clock_.CurrentTime());
}
TEST(CreateTimeControllerTest, CreatesNonNullController) {
FakeAlarm alarm(Timestamp::ms(100));
EXPECT_NE(CreateTimeController(&alarm), nullptr);
}
} // namespace
} // namespace webrtc

View File

@ -7,15 +7,17 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef TEST_TIME_CONTROLLER_TIME_CONTROLLER_H_
#define TEST_TIME_CONTROLLER_TIME_CONTROLLER_H_
#ifndef API_TEST_TIME_CONTROLLER_H_
#define API_TEST_TIME_CONTROLLER_H_
#include <functional>
#include <memory>
#include "api/task_queue/task_queue_factory.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "modules/utility/include/process_thread.h"
#include "rtc_base/synchronization/yield_policy.h"
#include "system_wrappers/include/clock.h"
namespace webrtc {
@ -42,6 +44,32 @@ class TimeController {
// might yield to execute other tasks. This allows doing blocking waits on
// tasks on other task queues froma a task queue without deadlocking.
virtual void InvokeWithControlledYield(std::function<void()> closure) = 0;
// Returns a YieldInterface which can be installed as a ScopedYieldPolicy.
virtual rtc::YieldInterface* YieldInterface() = 0;
};
// Interface for telling time, scheduling an event to fire at a particular time,
// and waiting for time to pass.
class ControlledAlarmClock {
public:
virtual ~ControlledAlarmClock() = default;
// Gets a clock that tells the alarm clock's notion of time.
virtual Clock* GetClock() = 0;
// Schedules the alarm to fire at |deadline|.
// An alarm clock only supports one deadline. Calls to |ScheduleAlarmAt| with
// an earlier deadline will reset the alarm to fire earlier.Calls to
// |ScheduleAlarmAt| with a later deadline are ignored. Returns true if the
// deadline changed, false otherwise.
virtual bool ScheduleAlarmAt(Timestamp deadline) = 0;
// Sets the callback that should be run when the alarm fires.
virtual void SetCallback(std::function<void()> callback) = 0;
// Waits for |duration| to pass, according to the alarm clock.
virtual void Sleep(TimeDelta duration) = 0;
};
} // namespace webrtc
#endif // TEST_TIME_CONTROLLER_TIME_CONTROLLER_H_
#endif // API_TEST_TIME_CONTROLLER_H_

View File

@ -41,6 +41,7 @@ rtc_library("emulated_network") {
deps = [
"../../api:network_emulation_manager_api",
"../../api:simulated_network_api",
"../../api:time_controller",
"../../api/units:data_rate",
"../../api/units:data_size",
"../../api/units:time_delta",

View File

@ -19,6 +19,7 @@
#include "api/test/network_emulation_manager.h"
#include "api/test/simulated_network.h"
#include "api/test/time_controller.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "rtc_base/logging.h"
@ -33,7 +34,6 @@
#include "test/network/network_emulation.h"
#include "test/network/simulated_network_node.h"
#include "test/network/traffic_route.h"
#include "test/time_controller/time_controller.h"
namespace webrtc {
namespace test {

View File

@ -84,6 +84,8 @@ if (rtc_include_tests) {
"../../api:libjingle_peerconnection_api",
"../../api:rtc_event_log_output_file",
"../../api:rtp_parameters",
"../../api:time_controller",
"../../api:time_controller",
"../../api:transport_api",
"../../api/audio_codecs:builtin_audio_decoder_factory",
"../../api/audio_codecs:builtin_audio_encoder_factory",

View File

@ -17,6 +17,7 @@
#include <vector>
#include "api/rtc_event_log/rtc_event_log.h"
#include "api/test/time_controller.h"
#include "call/call.h"
#include "modules/audio_device/include/test_audio_device.h"
#include "modules/congestion_controller/goog_cc/test/goog_cc_printer.h"
@ -28,7 +29,6 @@
#include "test/scenario/column_printer.h"
#include "test/scenario/network_node.h"
#include "test/scenario/scenario_config.h"
#include "test/time_controller/time_controller.h"
namespace webrtc {

View File

@ -14,6 +14,7 @@
#include <utility>
#include <vector>
#include "api/test/time_controller.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/fake_clock.h"
#include "rtc_base/task_queue.h"
@ -26,7 +27,6 @@
#include "test/scenario/network_node.h"
#include "test/scenario/scenario_config.h"
#include "test/scenario/video_stream.h"
#include "test/time_controller/time_controller.h"
namespace webrtc {
namespace test {

View File

@ -12,14 +12,16 @@ if (rtc_include_tests) {
rtc_library("time_controller") {
testonly = true
sources = [
"external_time_controller.cc",
"external_time_controller.h",
"real_time_controller.cc",
"real_time_controller.h",
"simulated_time_controller.cc",
"simulated_time_controller.h",
"time_controller.h",
]
deps = [
"../../api:time_controller",
"../../api/task_queue",
"../../api/task_queue:default_task_queue_factory",
"../../api/units:time_delta",
@ -39,6 +41,7 @@ if (rtc_include_tests) {
rtc_library("time_controller_unittests") {
testonly = true
sources = [
"external_time_controller_unittest.cc",
"simulated_time_controller_unittest.cc",
]
deps = [

View File

@ -0,0 +1,226 @@
/*
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "test/time_controller/external_time_controller.h"
#include <algorithm>
#include <map>
#include <memory>
#include <utility>
#include "api/task_queue/queued_task.h"
#include "api/task_queue/task_queue_base.h"
#include "api/task_queue/task_queue_factory.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "modules/include/module.h"
#include "modules/utility/include/process_thread.h"
#include "rtc_base/synchronization/yield_policy.h"
#include "test/time_controller/simulated_time_controller.h"
namespace webrtc {
// Wraps a ProcessThread so that it can reschedule the time controller whenever
// an external call changes the ProcessThread's state. For example, when a new
// module is registered, the ProcessThread may need to be called sooner than the
// time controller's currently-scheduled deadline.
class ExternalTimeController::ProcessThreadWrapper : public ProcessThread {
public:
ProcessThreadWrapper(ExternalTimeController* parent,
std::unique_ptr<ProcessThread> thread)
: parent_(parent), thread_(std::move(thread)) {}
void Start() override {
parent_->UpdateTime();
thread_->Start();
parent_->ScheduleNext();
}
void Stop() override {
parent_->UpdateTime();
thread_->Stop();
parent_->ScheduleNext();
}
void WakeUp(Module* module) override {
parent_->UpdateTime();
thread_->WakeUp(GetWrapper(module));
parent_->ScheduleNext();
}
void PostTask(std::unique_ptr<QueuedTask> task) override {
parent_->UpdateTime();
thread_->PostTask(std::move(task));
parent_->ScheduleNext();
}
void RegisterModule(Module* module, const rtc::Location& from) override {
parent_->UpdateTime();
module_wrappers_.emplace(module, new ModuleWrapper(module, this));
thread_->RegisterModule(GetWrapper(module), from);
parent_->ScheduleNext();
}
void DeRegisterModule(Module* module) override {
parent_->UpdateTime();
thread_->DeRegisterModule(GetWrapper(module));
parent_->ScheduleNext();
module_wrappers_.erase(module);
}
private:
class ModuleWrapper : public Module {
public:
ModuleWrapper(Module* module, ProcessThreadWrapper* thread)
: module_(module), thread_(thread) {}
int64_t TimeUntilNextProcess() override {
return module_->TimeUntilNextProcess();
}
void Process() override { module_->Process(); }
void ProcessThreadAttached(ProcessThread* process_thread) override {
if (process_thread) {
module_->ProcessThreadAttached(thread_);
} else {
module_->ProcessThreadAttached(nullptr);
}
}
private:
Module* module_;
ProcessThreadWrapper* thread_;
};
ModuleWrapper* GetWrapper(Module* module) {
auto it = module_wrappers_.find(module);
RTC_DCHECK(it != module_wrappers_.end());
return it->second.get();
}
ExternalTimeController* const parent_;
std::unique_ptr<ProcessThread> thread_;
std::map<Module*, std::unique_ptr<ModuleWrapper>> module_wrappers_;
};
// Wraps a TaskQueue so that it can reschedule the time controller whenever
// an external call schedules a new task.
class ExternalTimeController::TaskQueueWrapper : public TaskQueueBase {
public:
TaskQueueWrapper(ExternalTimeController* parent,
std::unique_ptr<TaskQueueBase, TaskQueueDeleter> base)
: parent_(parent), base_(std::move(base)) {}
void PostTask(std::unique_ptr<QueuedTask> task) override {
parent_->UpdateTime();
base_->PostTask(std::make_unique<TaskWrapper>(std::move(task), this));
parent_->ScheduleNext();
}
void PostDelayedTask(std::unique_ptr<QueuedTask> task, uint32_t ms) override {
parent_->UpdateTime();
base_->PostDelayedTask(std::make_unique<TaskWrapper>(std::move(task), this),
ms);
parent_->ScheduleNext();
}
void Delete() override { delete this; }
private:
class TaskWrapper : public QueuedTask {
public:
TaskWrapper(std::unique_ptr<QueuedTask> task, TaskQueueWrapper* queue)
: task_(std::move(task)), queue_(queue) {}
bool Run() override {
CurrentTaskQueueSetter current(queue_);
if (!task_->Run()) {
task_.release();
}
// The wrapper should always be deleted, even if it releases the inner
// task, in order to avoid leaking wrappers.
return true;
}
private:
std::unique_ptr<QueuedTask> task_;
TaskQueueWrapper* queue_;
};
ExternalTimeController* const parent_;
std::unique_ptr<TaskQueueBase, TaskQueueDeleter> base_;
};
ExternalTimeController::ExternalTimeController(ControlledAlarmClock* alarm)
: alarm_(alarm), impl_(alarm_->GetClock()->CurrentTime()) {
global_clock_.SetTime(alarm_->GetClock()->CurrentTime());
alarm_->SetCallback([this] { Run(); });
}
Clock* ExternalTimeController::GetClock() {
return alarm_->GetClock();
}
TaskQueueFactory* ExternalTimeController::GetTaskQueueFactory() {
return this;
}
std::unique_ptr<ProcessThread> ExternalTimeController::CreateProcessThread(
const char* thread_name) {
return std::make_unique<ProcessThreadWrapper>(
this, impl_.CreateProcessThread(thread_name));
}
void ExternalTimeController::Sleep(TimeDelta duration) {
alarm_->Sleep(duration);
}
void ExternalTimeController::InvokeWithControlledYield(
std::function<void()> closure) {
rtc::ScopedYieldPolicy policy(YieldInterface());
closure();
}
rtc::YieldInterface* ExternalTimeController::YieldInterface() {
return &impl_;
}
std::unique_ptr<TaskQueueBase, TaskQueueDeleter>
ExternalTimeController::CreateTaskQueue(
absl::string_view name,
TaskQueueFactory::Priority priority) const {
return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(
new TaskQueueWrapper(const_cast<ExternalTimeController*>(this),
impl_.CreateTaskQueue(name, priority)));
}
void ExternalTimeController::Run() {
rtc::ScopedYieldPolicy yield_policy(&impl_);
UpdateTime();
impl_.RunReadyRunners();
ScheduleNext();
}
void ExternalTimeController::UpdateTime() {
Timestamp now = alarm_->GetClock()->CurrentTime();
impl_.AdvanceTime(now);
global_clock_.SetTime(now);
}
void ExternalTimeController::ScheduleNext() {
RTC_DCHECK_EQ(impl_.CurrentTime(), alarm_->GetClock()->CurrentTime());
TimeDelta delay =
std::max(impl_.NextRunTime() - impl_.CurrentTime(), TimeDelta::Zero());
if (delay.IsFinite()) {
alarm_->ScheduleAlarmAt(alarm_->GetClock()->CurrentTime() + delay);
}
}
} // namespace webrtc

View File

@ -0,0 +1,70 @@
/*
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef TEST_TIME_CONTROLLER_EXTERNAL_TIME_CONTROLLER_H_
#define TEST_TIME_CONTROLLER_EXTERNAL_TIME_CONTROLLER_H_
#include <functional>
#include <memory>
#include "absl/strings/string_view.h"
#include "api/task_queue/task_queue_base.h"
#include "api/task_queue/task_queue_factory.h"
#include "api/test/time_controller.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "modules/utility/include/process_thread.h"
#include "system_wrappers/include/clock.h"
#include "test/time_controller/simulated_time_controller.h"
namespace webrtc {
// TimeController implementation built on an external controlled alarm.
// This implementation is used to delegate scheduling and execution to an
// external run loop.
class ExternalTimeController : public TimeController, public TaskQueueFactory {
public:
explicit ExternalTimeController(ControlledAlarmClock* alarm);
// Implementation of TimeController.
Clock* GetClock() override;
TaskQueueFactory* GetTaskQueueFactory() override;
std::unique_ptr<ProcessThread> CreateProcessThread(
const char* thread_name) override;
void Sleep(TimeDelta duration) override;
void InvokeWithControlledYield(std::function<void()> closure) override;
rtc::YieldInterface* YieldInterface() override;
// Implementation of TaskQueueFactory.
std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
absl::string_view name,
TaskQueueFactory::Priority priority) const override;
private:
class ProcessThreadWrapper;
class TaskQueueWrapper;
// Executes any tasks scheduled at or before the current time. May call
// |ScheduleNext| to schedule the next call to |Run|.
void Run();
void UpdateTime();
void ScheduleNext();
ControlledAlarmClock* alarm_;
sim_time_impl::SimulatedTimeControllerImpl impl_;
// Overrides the global rtc::Clock to ensure that it reports the same times as
// the time controller.
rtc::ScopedBaseFakeClock global_clock_;
};
} // namespace webrtc
#endif // TEST_TIME_CONTROLLER_EXTERNAL_TIME_CONTROLLER_H_

View File

@ -0,0 +1,181 @@
/*
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "test/time_controller/external_time_controller.h"
#include <atomic>
#include <memory>
#include <utility>
#include "rtc_base/event.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/task_utils/repeating_task.h"
#include "test/gmock.h"
#include "test/gtest.h"
// NOTE: Since these tests rely on real time behavior, they will be flaky
// if run on heavily loaded systems.
namespace webrtc {
namespace {
using ::testing::AtLeast;
using ::testing::Invoke;
using ::testing::MockFunction;
using ::testing::NiceMock;
using ::testing::Return;
constexpr Timestamp kStartTime = Timestamp::Seconds<1000>();
class FakeAlarm : public ControlledAlarmClock {
public:
explicit FakeAlarm(Timestamp start_time);
Clock* GetClock() override;
bool ScheduleAlarmAt(Timestamp deadline) override;
void SetCallback(std::function<void()> callback) override;
void Sleep(TimeDelta duration) override;
private:
SimulatedClock clock_;
Timestamp deadline_;
std::function<void()> callback_;
};
FakeAlarm::FakeAlarm(Timestamp start_time)
: clock_(start_time),
deadline_(Timestamp::PlusInfinity()),
callback_([] {}) {}
Clock* FakeAlarm::GetClock() {
return &clock_;
}
bool FakeAlarm::ScheduleAlarmAt(Timestamp deadline) {
if (deadline < deadline_) {
deadline_ = deadline;
return true;
}
return false;
}
void FakeAlarm::SetCallback(std::function<void()> callback) {
callback_ = callback;
}
void FakeAlarm::Sleep(TimeDelta duration) {
Timestamp end_time = clock_.CurrentTime() + duration;
while (deadline_ <= end_time) {
clock_.AdvanceTime(deadline_ - clock_.CurrentTime());
deadline_ = Timestamp::PlusInfinity();
callback_();
}
clock_.AdvanceTime(end_time - clock_.CurrentTime());
}
} // namespace
TEST(ExternalTimeControllerTest, TaskIsStoppedOnStop) {
const TimeDelta kShortInterval = TimeDelta::ms(5);
const TimeDelta kLongInterval = TimeDelta::ms(20);
const int kShortIntervalCount = 4;
const int kMargin = 1;
FakeAlarm alarm(kStartTime);
ExternalTimeController time_simulation(&alarm);
rtc::TaskQueue task_queue(
time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
"TestQueue", TaskQueueFactory::Priority::NORMAL));
std::atomic_int counter(0);
auto handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] {
if (++counter >= kShortIntervalCount)
return kLongInterval;
return kShortInterval;
});
// Sleep long enough to go through the initial phase.
time_simulation.Sleep(kShortInterval * (kShortIntervalCount + kMargin));
EXPECT_EQ(counter.load(), kShortIntervalCount);
task_queue.PostTask(
[handle = std::move(handle)]() mutable { handle.Stop(); });
// Sleep long enough that the task would run at least once more if not
// stopped.
time_simulation.Sleep(kLongInterval * 2);
EXPECT_EQ(counter.load(), kShortIntervalCount);
}
TEST(ExternalTimeControllerTest, TaskCanStopItself) {
std::atomic_int counter(0);
FakeAlarm alarm(kStartTime);
ExternalTimeController time_simulation(&alarm);
rtc::TaskQueue task_queue(
time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
"TestQueue", TaskQueueFactory::Priority::NORMAL));
RepeatingTaskHandle handle;
task_queue.PostTask([&] {
handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] {
++counter;
handle.Stop();
return TimeDelta::ms(2);
});
});
time_simulation.Sleep(TimeDelta::ms(10));
EXPECT_EQ(counter.load(), 1);
}
TEST(ExternalTimeControllerTest, YieldForTask) {
FakeAlarm alarm(kStartTime);
ExternalTimeController time_simulation(&alarm);
rtc::TaskQueue task_queue(
time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
"TestQueue", TaskQueueFactory::Priority::NORMAL));
time_simulation.InvokeWithControlledYield([&] {
rtc::Event event;
task_queue.PostTask([&] { event.Set(); });
EXPECT_TRUE(event.Wait(200));
});
}
TEST(ExternalTimeControllerTest, TasksYieldToEachOther) {
FakeAlarm alarm(kStartTime);
ExternalTimeController time_simulation(&alarm);
rtc::TaskQueue task_queue(
time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
"TestQueue", TaskQueueFactory::Priority::NORMAL));
rtc::TaskQueue other_queue(
time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
"OtherQueue", TaskQueueFactory::Priority::NORMAL));
task_queue.PostTask([&] {
rtc::Event event;
other_queue.PostTask([&] { event.Set(); });
EXPECT_TRUE(event.Wait(200));
});
time_simulation.Sleep(TimeDelta::ms(300));
}
TEST(ExternalTimeControllerTest, CurrentTaskQueue) {
FakeAlarm alarm(kStartTime);
ExternalTimeController time_simulation(&alarm);
rtc::TaskQueue task_queue(
time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
"TestQueue", TaskQueueFactory::Priority::NORMAL));
task_queue.PostTask([&] { EXPECT_TRUE(task_queue.IsCurrent()); });
time_simulation.Sleep(TimeDelta::ms(10));
}
} // namespace webrtc

View File

@ -39,6 +39,10 @@ void RealTimeController::InvokeWithControlledYield(
closure();
}
rtc::YieldInterface* RealTimeController::YieldInterface() {
return nullptr;
}
RealTimeController* GlobalRealTimeController() {
static RealTimeController* time_controller = new RealTimeController();
return time_controller;

View File

@ -14,10 +14,10 @@
#include <memory>
#include "api/task_queue/task_queue_factory.h"
#include "api/test/time_controller.h"
#include "api/units/time_delta.h"
#include "modules/utility/include/process_thread.h"
#include "system_wrappers/include/clock.h"
#include "test/time_controller/time_controller.h"
namespace webrtc {
class RealTimeController : public TimeController {
@ -30,6 +30,7 @@ class RealTimeController : public TimeController {
const char* thread_name) override;
void Sleep(TimeDelta duration) override;
void InvokeWithControlledYield(std::function<void()> closure) override;
rtc::YieldInterface* YieldInterface() override;
private:
std::unique_ptr<TaskQueueFactory> task_queue_factory_;

View File

@ -440,6 +440,10 @@ void GlobalSimulatedTimeController::InvokeWithControlledYield(
closure();
}
rtc::YieldInterface* GlobalSimulatedTimeController::YieldInterface() {
return &impl_;
}
// namespace sim_time_impl
} // namespace webrtc

View File

@ -16,6 +16,7 @@
#include <utility>
#include <vector>
#include "api/test/time_controller.h"
#include "api/units/timestamp.h"
#include "modules/include/module.h"
#include "modules/utility/include/process_thread.h"
@ -24,7 +25,6 @@
#include "rtc_base/platform_thread_types.h"
#include "rtc_base/synchronization/yield_policy.h"
#include "rtc_base/thread_checker.h"
#include "test/time_controller/time_controller.h"
namespace webrtc {
@ -92,6 +92,7 @@ class GlobalSimulatedTimeController : public TimeController {
const char* thread_name) override;
void Sleep(TimeDelta duration) override;
void InvokeWithControlledYield(std::function<void()> closure) override;
rtc::YieldInterface* YieldInterface() override;
private:
rtc::ScopedBaseFakeClock global_clock_;