Adds simulated time controller

This CL introduces the TimeControllerInterface that provides timing
related functionality. Most notably it provides a TaskQueueFactory
and facilitates creation of ProcessThread.

Two implementations of the interface are provided, RealTimeController
and SimulatedTimeController.

This prepares for an upcoming CL using these in Scenario tests.

Bug: webrtc:10365
Change-Id: Id956a29628d7e2f53ecaedadd643a9f697329d2f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/127297
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27244}
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 3ef0827f..0bb85b1 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -392,6 +392,7 @@
       "../test:single_threaded_task_queue",
       "pc/e2e:e2e_unittests",
       "scenario:scenario_unittests",
+      "time_controller:time_controller_unittests",
       "//testing/gmock",
       "//testing/gtest",
       "//third_party/abseil-cpp/absl/memory",
diff --git a/test/time_controller/BUILD.gn b/test/time_controller/BUILD.gn
new file mode 100644
index 0000000..eb75af6
--- /dev/null
+++ b/test/time_controller/BUILD.gn
@@ -0,0 +1,54 @@
+# Copyright (c) 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.
+
+import("../../webrtc.gni")
+
+if (rtc_include_tests) {
+  rtc_source_set("time_controller") {
+    testonly = true
+    sources = [
+      "real_time_controller.cc",
+      "real_time_controller.h",
+      "simulated_time_controller.cc",
+      "simulated_time_controller.h",
+      "time_controller.h",
+    ]
+
+    deps = [
+      "../../api/task_queue",
+      "../../api/task_queue:global_task_queue_factory",
+      "../../api/units:time_delta",
+      "../../api/units:timestamp",
+      "../../modules:module_api",
+      "../../modules/utility:utility",
+      "../../rtc_base",
+      "../../rtc_base:rtc_base_tests_utils",
+      "../../rtc_base:rtc_event",
+      "../../rtc_base:sequenced_task_checker",
+      "../../rtc_base/synchronization:yield_policy",
+      "../../rtc_base/task_utils:to_queued_task",
+      "../../system_wrappers",
+      "//third_party/abseil-cpp/absl/memory",
+      "//third_party/abseil-cpp/absl/strings",
+    ]
+  }
+  rtc_source_set("time_controller_unittests") {
+    testonly = true
+    sources = [
+      "simulated_time_controller_unittest.cc",
+    ]
+    deps = [
+      ":time_controller",
+      "../:test_support",
+      "../../rtc_base:rtc_base_approved",
+      "../../rtc_base:rtc_task_queue",
+      "../../rtc_base/task_utils:repeating_task",
+      "//third_party/abseil-cpp/absl/memory",
+    ]
+  }
+}
diff --git a/test/time_controller/real_time_controller.cc b/test/time_controller/real_time_controller.cc
new file mode 100644
index 0000000..7ad9eef
--- /dev/null
+++ b/test/time_controller/real_time_controller.cc
@@ -0,0 +1,41 @@
+/*
+ *  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/real_time_controller.h"
+
+#include "api/task_queue/global_task_queue_factory.h"
+#include "rtc_base/event.h"
+#include "rtc_base/task_utils/to_queued_task.h"
+#include "system_wrappers/include/sleep.h"
+
+namespace webrtc {
+
+Clock* RealTimeController::GetClock() {
+  return Clock::GetRealTimeClock();
+}
+
+TaskQueueFactory* RealTimeController::GetTaskQueueFactory() {
+  return &GlobalTaskQueueFactory();
+}
+
+std::unique_ptr<ProcessThread> RealTimeController::CreateProcessThread(
+    const char* thread_name) {
+  return ProcessThread::Create(thread_name);
+}
+
+void RealTimeController::Sleep(TimeDelta duration) {
+  SleepMs(duration.ms());
+}
+
+void RealTimeController::InvokeWithControlledYield(
+    std::function<void()> closure) {
+  closure();
+}
+
+}  // namespace webrtc
diff --git a/test/time_controller/real_time_controller.h b/test/time_controller/real_time_controller.h
new file mode 100644
index 0000000..05cfc93
--- /dev/null
+++ b/test/time_controller/real_time_controller.h
@@ -0,0 +1,30 @@
+/*
+ *  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_REAL_TIME_CONTROLLER_H_
+#define TEST_TIME_CONTROLLER_REAL_TIME_CONTROLLER_H_
+
+#include <memory>
+
+#include "test/time_controller/time_controller.h"
+
+namespace webrtc {
+class RealTimeController : public TimeController {
+ public:
+  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;
+};
+
+}  // namespace webrtc
+
+#endif  // TEST_TIME_CONTROLLER_REAL_TIME_CONTROLLER_H_
diff --git a/test/time_controller/simulated_time_controller.cc b/test/time_controller/simulated_time_controller.cc
new file mode 100644
index 0000000..144d587
--- /dev/null
+++ b/test/time_controller/simulated_time_controller.cc
@@ -0,0 +1,415 @@
+/*
+ *  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/simulated_time_controller.h"
+
+#include <algorithm>
+#include <deque>
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+
+namespace webrtc {
+
+namespace sim_time_impl {
+class SimulatedSequenceRunner : public ProcessThread, public TaskQueueBase {
+ public:
+  SimulatedSequenceRunner(SimulatedTimeControllerImpl* handler,
+                          absl::string_view queue_name)
+      : handler_(handler), name_(queue_name) {}
+  ~SimulatedSequenceRunner() override { handler_->Unregister(this); }
+
+  // Provides next run time.
+  Timestamp GetNextRunTime() const;
+
+  // Iterates through delayed tasks and modules and moves them to the ready set
+  // if they are supposed to execute by |at time|.
+  void UpdateReady(Timestamp at_time);
+  // Runs all ready tasks and modules and updates next run time.
+  void Run(Timestamp at_time);
+
+  // TaskQueueBase interface
+  void Delete() override;
+  // Note: PostTask is also in ProcessThread interface.
+  void PostTask(std::unique_ptr<QueuedTask> task) override;
+  void PostDelayedTask(std::unique_ptr<QueuedTask> task,
+                       uint32_t milliseconds) override;
+
+  // ProcessThread interface
+  void Start() override;
+  void Stop() override;
+  void WakeUp(Module* module) override;
+  void RegisterModule(Module* module, const rtc::Location& from) override;
+  void DeRegisterModule(Module* module) override;
+
+ private:
+  Timestamp GetCurrentTime() const { return handler_->CurrentTime(); }
+  void RunReadyTasks(Timestamp at_time) RTC_LOCKS_EXCLUDED(lock_);
+  void RunReadyModules(Timestamp at_time) RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  void UpdateNextRunTime() RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+  SimulatedTimeControllerImpl* const handler_;
+  const std::string name_;
+
+  rtc::CriticalSection lock_;
+
+  std::deque<std::unique_ptr<QueuedTask>> ready_tasks_ RTC_GUARDED_BY(lock_);
+  std::multimap<Timestamp, std::unique_ptr<QueuedTask>> delayed_tasks_
+      RTC_GUARDED_BY(lock_);
+
+  bool process_thread_running_ RTC_GUARDED_BY(lock_) = false;
+  std::set<Module*> stopped_modules_ RTC_GUARDED_BY(lock_);
+  std::set<Module*> ready_modules_ RTC_GUARDED_BY(lock_);
+  std::multimap<Timestamp, Module*> delayed_modules_ RTC_GUARDED_BY(lock_);
+
+  Timestamp next_run_time_ RTC_GUARDED_BY(lock_) = Timestamp::PlusInfinity();
+};
+
+Timestamp SimulatedSequenceRunner::GetNextRunTime() const {
+  rtc::CritScope lock(&lock_);
+  return next_run_time_;
+}
+
+void SimulatedSequenceRunner::UpdateReady(Timestamp at_time) {
+  rtc::CritScope lock(&lock_);
+  for (auto it = delayed_tasks_.begin();
+       it != delayed_tasks_.end() && it->first <= at_time;) {
+    ready_tasks_.emplace_back(std::move(it->second));
+    it = delayed_tasks_.erase(it);
+  }
+  for (auto it = delayed_modules_.begin();
+       it != delayed_modules_.end() && it->first <= at_time;) {
+    ready_modules_.insert(it->second);
+    it = delayed_modules_.erase(it);
+  }
+}
+
+void SimulatedSequenceRunner::Run(Timestamp at_time) {
+  RunReadyTasks(at_time);
+  rtc::CritScope lock(&lock_);
+  RunReadyModules(at_time);
+  UpdateNextRunTime();
+}
+
+void SimulatedSequenceRunner::Delete() {
+  {
+    rtc::CritScope lock(&lock_);
+    ready_tasks_.clear();
+    delayed_tasks_.clear();
+  }
+  delete this;
+}
+
+void SimulatedSequenceRunner::RunReadyTasks(Timestamp at_time) {
+  std::deque<std::unique_ptr<QueuedTask>> ready_tasks;
+  {
+    rtc::CritScope lock(&lock_);
+    ready_tasks.swap(ready_tasks_);
+  }
+  if (!ready_tasks.empty()) {
+    CurrentTaskQueueSetter set_current(this);
+    for (auto& ready : ready_tasks) {
+      bool delete_task = ready->Run();
+      if (delete_task) {
+        ready.reset();
+      } else {
+        ready.release();
+      }
+    }
+  }
+}
+
+void SimulatedSequenceRunner::RunReadyModules(Timestamp at_time) {
+  if (!ready_modules_.empty()) {
+    CurrentTaskQueueSetter set_current(this);
+    for (auto* module : ready_modules_) {
+      module->Process();
+      Timestamp next_run_time =
+          at_time + TimeDelta::ms(module->TimeUntilNextProcess());
+      delayed_modules_.emplace(next_run_time, module);
+    }
+  }
+  ready_modules_.clear();
+}
+
+void SimulatedSequenceRunner::UpdateNextRunTime() {
+  if (!ready_tasks_.empty() || !ready_modules_.empty()) {
+    next_run_time_ = Timestamp::MinusInfinity();
+  } else {
+    next_run_time_ = Timestamp::PlusInfinity();
+    if (!delayed_tasks_.empty())
+      next_run_time_ = std::min(next_run_time_, delayed_tasks_.begin()->first);
+    if (!delayed_modules_.empty())
+      next_run_time_ =
+          std::min(next_run_time_, delayed_modules_.begin()->first);
+  }
+}
+
+void SimulatedSequenceRunner::PostTask(std::unique_ptr<QueuedTask> task) {
+  rtc::CritScope lock(&lock_);
+  ready_tasks_.emplace_back(std::move(task));
+  next_run_time_ = Timestamp::MinusInfinity();
+}
+
+void SimulatedSequenceRunner::PostDelayedTask(std::unique_ptr<QueuedTask> task,
+                                              uint32_t milliseconds) {
+  rtc::CritScope lock(&lock_);
+  Timestamp target_time = GetCurrentTime() + TimeDelta::ms(milliseconds);
+  delayed_tasks_.emplace(target_time, std::move(task));
+  next_run_time_ = std::min(next_run_time_, target_time);
+}
+
+void SimulatedSequenceRunner::Start() {
+  std::set<Module*> starting;
+  {
+    rtc::CritScope lock(&lock_);
+    if (process_thread_running_)
+      return;
+    process_thread_running_ = true;
+    starting.swap(stopped_modules_);
+  }
+  for (auto& module : starting)
+    module->ProcessThreadAttached(this);
+
+  Timestamp at_time = GetCurrentTime();
+  rtc::CritScope lock(&lock_);
+  for (auto& module : starting)
+    delayed_modules_.insert(
+        {at_time + TimeDelta::ms(module->TimeUntilNextProcess()), module});
+  UpdateNextRunTime();
+}
+
+void SimulatedSequenceRunner::Stop() {
+  std::set<Module*> stopping;
+  {
+    rtc::CritScope lock(&lock_);
+    process_thread_running_ = false;
+
+    for (auto* ready : ready_modules_)
+      stopped_modules_.insert(ready);
+    ready_modules_.clear();
+
+    for (auto& delayed : delayed_modules_)
+      stopped_modules_.insert(delayed.second);
+    delayed_modules_.clear();
+
+    stopping = stopped_modules_;
+  }
+  for (auto& module : stopping)
+    module->ProcessThreadAttached(nullptr);
+}
+
+void SimulatedSequenceRunner::WakeUp(Module* module) {
+  rtc::CritScope lock(&lock_);
+  // If we already are planning to run this module as soon as possible, we don't
+  // need to do anything.
+  if (ready_modules_.find(module) != ready_modules_.end())
+    return;
+
+  for (auto it = delayed_modules_.begin(); it != delayed_modules_.end(); ++it) {
+    if (it->second == module) {
+      delayed_modules_.erase(it);
+      break;
+    }
+  }
+  Timestamp next_time =
+      GetCurrentTime() + TimeDelta::ms(module->TimeUntilNextProcess());
+  delayed_modules_.insert({next_time, module});
+  next_run_time_ = std::min(next_run_time_, next_time);
+}
+
+void SimulatedSequenceRunner::RegisterModule(Module* module,
+                                             const rtc::Location& from) {
+  module->ProcessThreadAttached(this);
+  rtc::CritScope lock(&lock_);
+  if (!process_thread_running_) {
+    stopped_modules_.insert(module);
+  } else {
+    Timestamp next_time =
+        GetCurrentTime() + TimeDelta::ms(module->TimeUntilNextProcess());
+    delayed_modules_.insert({next_time, module});
+    next_run_time_ = std::min(next_run_time_, next_time);
+  }
+}
+
+void SimulatedSequenceRunner::DeRegisterModule(Module* module) {
+  bool modules_running;
+  {
+    rtc::CritScope lock(&lock_);
+    if (!process_thread_running_) {
+      stopped_modules_.erase(module);
+    } else {
+      ready_modules_.erase(module);
+      for (auto it = delayed_modules_.begin(); it != delayed_modules_.end();
+           ++it) {
+        if (it->second == module) {
+          delayed_modules_.erase(it);
+          break;
+        }
+      }
+    }
+    modules_running = process_thread_running_;
+  }
+  if (modules_running)
+    module->ProcessThreadAttached(nullptr);
+}
+
+SimulatedTimeControllerImpl::SimulatedTimeControllerImpl(Timestamp start_time)
+    : thread_id_(rtc::CurrentThreadId()), current_time_(start_time) {}
+
+SimulatedTimeControllerImpl::~SimulatedTimeControllerImpl() = default;
+
+std::unique_ptr<TaskQueueBase, TaskQueueDeleter>
+SimulatedTimeControllerImpl::CreateTaskQueue(
+    absl::string_view name,
+    TaskQueueFactory::Priority priority) const {
+  // TODO(srte): Remove the const cast when the interface is made mutable.
+  auto mutable_this = const_cast<SimulatedTimeControllerImpl*>(this);
+  auto task_queue = std::unique_ptr<SimulatedSequenceRunner, TaskQueueDeleter>(
+      new SimulatedSequenceRunner(mutable_this, name));
+  rtc::CritScope lock(&mutable_this->lock_);
+  mutable_this->runners_.insert(task_queue.get());
+  return task_queue;
+}
+
+std::unique_ptr<ProcessThread> SimulatedTimeControllerImpl::CreateProcessThread(
+    const char* thread_name) {
+  rtc::CritScope lock(&lock_);
+  auto process_thread =
+      absl::make_unique<SimulatedSequenceRunner>(this, thread_name);
+  runners_.insert(process_thread.get());
+  return process_thread;
+}
+
+std::vector<SimulatedSequenceRunner*>
+SimulatedTimeControllerImpl::GetNextReadyRunner(Timestamp current_time) {
+  rtc::CritScope lock(&lock_);
+  std::vector<SimulatedSequenceRunner*> ready;
+  for (auto* runner : runners_) {
+    if (yielded_.find(runner) == yielded_.end() &&
+        runner->GetNextRunTime() <= current_time) {
+      ready.push_back(runner);
+    }
+  }
+  return ready;
+}
+
+void SimulatedTimeControllerImpl::YieldExecution() {
+  if (rtc::CurrentThreadId() == thread_id_) {
+    RTC_DCHECK_RUN_ON(&thread_checker_);
+    // When we yield, we don't want to risk executing further tasks on the
+    // currently executing task queue. If there's a ready task that also yields,
+    // it's added to this set as well and only tasks on the remaining task
+    // queues are executed.
+    auto inserted = yielded_.insert(TaskQueueBase::Current());
+    RTC_DCHECK(inserted.second);
+    RunReadyRunners();
+    yielded_.erase(inserted.first);
+  }
+}
+
+void SimulatedTimeControllerImpl::RunReadyRunners() {
+  RTC_DCHECK_RUN_ON(&thread_checker_);
+  Timestamp current_time = CurrentTime();
+  // We repeat until we have no ready left to handle tasks posted by ready
+  // runners.
+  while (true) {
+    auto ready = GetNextReadyRunner(current_time);
+    if (ready.empty())
+      break;
+    for (auto* runner : ready) {
+      runner->UpdateReady(current_time);
+      runner->Run(current_time);
+    }
+  }
+}
+
+Timestamp SimulatedTimeControllerImpl::CurrentTime() const {
+  rtc::CritScope lock(&time_lock_);
+  return current_time_;
+}
+
+Timestamp SimulatedTimeControllerImpl::NextRunTime() const {
+  Timestamp current_time = CurrentTime();
+  Timestamp next_time = Timestamp::PlusInfinity();
+  rtc::CritScope lock(&lock_);
+  for (auto* runner : runners_) {
+    Timestamp next_run_time = runner->GetNextRunTime();
+    if (next_run_time <= current_time)
+      return current_time;
+    next_time = std::min(next_time, next_run_time);
+  }
+  return next_time;
+}
+
+void SimulatedTimeControllerImpl::AdvanceTime(Timestamp target_time) {
+  rtc::CritScope time_lock(&time_lock_);
+  RTC_DCHECK(target_time >= current_time_);
+  current_time_ = target_time;
+}
+
+void SimulatedTimeControllerImpl::Unregister(SimulatedSequenceRunner* runner) {
+  rtc::CritScope lock(&lock_);
+  RTC_CHECK(runners_.erase(runner));
+}
+
+}  // namespace sim_time_impl
+
+GlobalSimulatedTimeController::GlobalSimulatedTimeController(
+    Timestamp start_time)
+    : sim_clock_(start_time.us()), impl_(start_time) {
+  global_clock_.SetTimeMicros(start_time.us());
+}
+
+GlobalSimulatedTimeController::~GlobalSimulatedTimeController() = default;
+
+Clock* GlobalSimulatedTimeController::GetClock() {
+  return &sim_clock_;
+}
+
+TaskQueueFactory* GlobalSimulatedTimeController::GetTaskQueueFactory() {
+  return &impl_;
+}
+
+std::unique_ptr<ProcessThread>
+GlobalSimulatedTimeController::CreateProcessThread(const char* thread_name) {
+  return impl_.CreateProcessThread(thread_name);
+}
+
+void GlobalSimulatedTimeController::Sleep(TimeDelta duration) {
+  rtc::ScopedYieldPolicy yield_policy(&impl_);
+  Timestamp current_time = impl_.CurrentTime();
+  Timestamp target_time = current_time + duration;
+  RTC_DCHECK_EQ(current_time.us(), rtc::TimeMicros());
+  while (current_time < target_time) {
+    impl_.RunReadyRunners();
+    Timestamp next_time = std::min(impl_.NextRunTime(), target_time);
+    impl_.AdvanceTime(next_time);
+    auto delta = next_time - current_time;
+    current_time = next_time;
+    sim_clock_.AdvanceTimeMicroseconds(delta.us());
+    global_clock_.AdvanceTimeMicros(delta.us());
+  }
+}
+
+void GlobalSimulatedTimeController::InvokeWithControlledYield(
+    std::function<void()> closure) {
+  rtc::ScopedYieldPolicy yield_policy(&impl_);
+  closure();
+}
+
+// namespace sim_time_impl
+
+}  // namespace webrtc
diff --git a/test/time_controller/simulated_time_controller.h b/test/time_controller/simulated_time_controller.h
new file mode 100644
index 0000000..38a9984
--- /dev/null
+++ b/test/time_controller/simulated_time_controller.h
@@ -0,0 +1,102 @@
+/*
+ *  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_SIMULATED_TIME_CONTROLLER_H_
+#define TEST_TIME_CONTROLLER_SIMULATED_TIME_CONTROLLER_H_
+
+#include <memory>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "api/units/timestamp.h"
+#include "modules/include/module.h"
+#include "modules/utility/include/process_thread.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/fake_clock.h"
+#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 {
+
+namespace sim_time_impl {
+class SimulatedSequenceRunner;
+
+class SimulatedTimeControllerImpl : public TaskQueueFactory,
+                                    public rtc::YieldInterface {
+ public:
+  explicit SimulatedTimeControllerImpl(Timestamp start_time);
+  ~SimulatedTimeControllerImpl() override;
+
+  std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+      absl::string_view name,
+      Priority priority) const override;
+
+  // Implements the YieldInterface by running ready tasks on all task queues,
+  // except that if this method is called from a task, the task queue running
+  // that task is skipped.
+  void YieldExecution() override;
+  // Create process thread with the name |thread_name|.
+  std::unique_ptr<ProcessThread> CreateProcessThread(const char* thread_name);
+  // Runs all runners in |runners_| that has tasks or modules ready for
+  // execution.
+  void RunReadyRunners();
+  // Return |current_time_|.
+  Timestamp CurrentTime() const;
+  // Return min of runner->GetNextRunTime() for runner in |runners_|.
+  Timestamp NextRunTime() const;
+  // Set |current_time_| to |target_time|.
+  void AdvanceTime(Timestamp target_time);
+  // Removes |runner| from |runners_|.
+  void Unregister(SimulatedSequenceRunner* runner);
+
+ private:
+  // Returns runners in |runners_| that are ready for execution.
+  std::vector<SimulatedSequenceRunner*> GetNextReadyRunner(
+      Timestamp current_time) RTC_RUN_ON(thread_checker_);
+
+  const rtc::PlatformThreadId thread_id_;
+  rtc::ThreadChecker thread_checker_;
+  rtc::CriticalSection time_lock_;
+  Timestamp current_time_ RTC_GUARDED_BY(time_lock_);
+  rtc::CriticalSection lock_;
+  std::unordered_set<SimulatedSequenceRunner*> runners_ RTC_GUARDED_BY(lock_);
+  // Task queues on which YieldExecution has been called.
+  std::unordered_set<TaskQueueBase*> yielded_ RTC_GUARDED_BY(thread_checker_);
+};
+}  // namespace sim_time_impl
+
+// TimeController implementation using completely simulated time. Task queues
+// and process threads created by this controller will run delayed activities
+// when Sleep() is called. Overrides the global clock backing rtc::TimeMillis()
+// and rtc::TimeMicros(). Note that this is not thread safe since it modifies
+// global state.
+class GlobalSimulatedTimeController : public TimeController {
+ public:
+  explicit GlobalSimulatedTimeController(Timestamp start_time);
+  ~GlobalSimulatedTimeController() override;
+
+  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;
+
+ private:
+  rtc::ScopedFakeClock global_clock_;
+  // Provides simulated CurrentNtpInMilliseconds()
+  SimulatedClock sim_clock_;
+  sim_time_impl::SimulatedTimeControllerImpl impl_;
+};
+}  // namespace webrtc
+
+#endif  // TEST_TIME_CONTROLLER_SIMULATED_TIME_CONTROLLER_H_
diff --git a/test/time_controller/simulated_time_controller_unittest.cc b/test/time_controller/simulated_time_controller_unittest.cc
new file mode 100644
index 0000000..6eb5211
--- /dev/null
+++ b/test/time_controller/simulated_time_controller_unittest.cc
@@ -0,0 +1,120 @@
+/*
+ *  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 <atomic>
+#include <memory>
+
+#include "absl/memory/memory.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/task_utils/repeating_task.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/time_controller/simulated_time_controller.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>();
+
+// Helper closure class to stop repeating task on a task queue. This is
+// equivalent to [handle{move(handle)}] { handle.Stop(); } in c++14.
+class TaskHandleStopper {
+ public:
+  explicit TaskHandleStopper(RepeatingTaskHandle handle)
+      : handle_(std::move(handle)) {}
+  void operator()() { handle_.Stop(); }
+
+ private:
+  RepeatingTaskHandle handle_;
+};
+}  // namespace
+
+TEST(SimulatedTimeControllerTest, TaskIsStoppedOnStop) {
+  const TimeDelta kShortInterval = TimeDelta::ms(5);
+  const TimeDelta kLongInterval = TimeDelta::ms(20);
+  const int kShortIntervalCount = 4;
+  const int kMargin = 1;
+  GlobalSimulatedTimeController time_simulation(kStartTime);
+  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(TaskHandleStopper(std::move(handle)));
+  // 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(SimulatedTimeControllerTest, TaskCanStopItself) {
+  std::atomic_int counter(0);
+  GlobalSimulatedTimeController time_simulation(kStartTime);
+  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(SimulatedTimeControllerTest, Example) {
+  class ObjectOnTaskQueue {
+   public:
+    void DoPeriodicTask() {}
+    TimeDelta TimeUntilNextRun() { return TimeDelta::ms(100); }
+    void StartPeriodicTask(RepeatingTaskHandle* handle,
+                           rtc::TaskQueue* task_queue) {
+      *handle = RepeatingTaskHandle::Start(task_queue->Get(), [this] {
+        DoPeriodicTask();
+        return TimeUntilNextRun();
+      });
+    }
+  };
+  GlobalSimulatedTimeController time_simulation(kStartTime);
+  rtc::TaskQueue task_queue(
+      time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+          "TestQueue", TaskQueueFactory::Priority::NORMAL));
+  auto object = absl::make_unique<ObjectOnTaskQueue>();
+  // Create and start the periodic task.
+  RepeatingTaskHandle handle;
+  object->StartPeriodicTask(&handle, &task_queue);
+  // Restart the task
+  task_queue.PostTask(TaskHandleStopper(std::move(handle)));
+  object->StartPeriodicTask(&handle, &task_queue);
+  task_queue.PostTask(TaskHandleStopper(std::move(handle)));
+  struct Destructor {
+    void operator()() { object.reset(); }
+    std::unique_ptr<ObjectOnTaskQueue> object;
+  };
+  task_queue.PostTask(Destructor{std::move(object)});
+}
+}  // namespace webrtc
diff --git a/test/time_controller/time_controller.h b/test/time_controller/time_controller.h
new file mode 100644
index 0000000..5d97e27
--- /dev/null
+++ b/test/time_controller/time_controller.h
@@ -0,0 +1,47 @@
+/*
+ *  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_TIME_CONTROLLER_H_
+#define TEST_TIME_CONTROLLER_TIME_CONTROLLER_H_
+
+#include <functional>
+#include <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+#include "api/units/time_delta.h"
+#include "modules/utility/include/process_thread.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+
+// Interface for controlling time progress. This allows us to execute test code
+// in either real time or simulated time by using different implementation of
+// this interface.
+class TimeController {
+ public:
+  virtual ~TimeController() = default;
+  // Provides a clock instance that follows implementation defined time
+  // progress.
+  virtual Clock* GetClock() = 0;
+  // The returned factory will created task queues that runs in implementation
+  // defined time domain.
+  virtual TaskQueueFactory* GetTaskQueueFactory() = 0;
+  // Creates a process thread.
+  virtual std::unique_ptr<ProcessThread> CreateProcessThread(
+      const char* thread_name) = 0;
+  // Allow task queues and process threads created by this instance to execute
+  // for the given |duration|.
+  virtual void Sleep(TimeDelta duration) = 0;
+  // Execute closure in an implementation defined scope where rtc::Event::Wait
+  // 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;
+};
+}  // namespace webrtc
+#endif  // TEST_TIME_CONTROLLER_TIME_CONTROLLER_H_