• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "platform/test/fake_task_runner.h"
6 
7 #include <utility>
8 
9 #include "util/osp_logging.h"
10 
11 namespace openscreen {
12 
FakeTaskRunner(FakeClock * clock)13 FakeTaskRunner::FakeTaskRunner(FakeClock* clock) : clock_(clock) {
14   OSP_CHECK(clock_);
15   clock_->SubscribeToTimeChanges(this);
16 }
17 
~FakeTaskRunner()18 FakeTaskRunner::~FakeTaskRunner() {
19   clock_->UnsubscribeFromTimeChanges(this);
20 }
21 
RunTasksUntilIdle()22 void FakeTaskRunner::RunTasksUntilIdle() {
23   // If there is bad code that posts tasks indefinitely, this loop will never
24   // break. However, that also means there is a code path spinning a CPU core at
25   // 100% all the time. Rather than mitigate this problem scenario, purposely
26   // let it manifest here in the hopes that unit testing will reveal it (e.g., a
27   // unit test that never finishes running).
28   for (;;) {
29     const auto current_time = FakeClock::now();
30     const auto end_of_range = delayed_tasks_.upper_bound(current_time);
31     for (auto it = delayed_tasks_.begin(); it != end_of_range; ++it) {
32       ready_to_run_tasks_.push_back(std::move(it->second));
33     }
34     delayed_tasks_.erase(delayed_tasks_.begin(), end_of_range);
35 
36     if (ready_to_run_tasks_.empty()) {
37       break;
38     }
39 
40     std::vector<Task> running_tasks;
41     running_tasks.swap(ready_to_run_tasks_);
42     for (Task& running_task : running_tasks) {
43       // Move the task out of the vector and onto the stack so that it destroys
44       // just after being run. This helps catch "dangling reference/pointer"
45       // bugs.
46       Task task = std::move(running_task);
47       task();
48     }
49   }
50 }
51 
PostPackagedTask(Task task)52 void FakeTaskRunner::PostPackagedTask(Task task) {
53   ready_to_run_tasks_.push_back(std::move(task));
54 }
55 
PostPackagedTaskWithDelay(Task task,Clock::duration delay)56 void FakeTaskRunner::PostPackagedTaskWithDelay(Task task,
57                                                Clock::duration delay) {
58   delayed_tasks_.emplace(
59       std::make_pair(FakeClock::now() + delay, std::move(task)));
60 }
61 
IsRunningOnTaskRunner()62 bool FakeTaskRunner::IsRunningOnTaskRunner() {
63   return true;
64 }
65 
GetResumeTime() const66 Clock::time_point FakeTaskRunner::GetResumeTime() const {
67   if (!ready_to_run_tasks_.empty()) {
68     return FakeClock::now();
69   }
70   if (!delayed_tasks_.empty()) {
71     return delayed_tasks_.begin()->first;
72   }
73   return Clock::time_point::max();
74 }
75 
76 }  // namespace openscreen
77