xref: /aosp_15_r20/external/openscreen/platform/test/fake_clock.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2018 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #include "platform/test/fake_clock.h"
6*3f982cf4SFabien Sanglard 
7*3f982cf4SFabien Sanglard #include <algorithm>
8*3f982cf4SFabien Sanglard 
9*3f982cf4SFabien Sanglard #include "platform/test/fake_task_runner.h"
10*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
11*3f982cf4SFabien Sanglard 
12*3f982cf4SFabien Sanglard namespace openscreen {
13*3f982cf4SFabien Sanglard 
14*3f982cf4SFabien Sanglard namespace {
15*3f982cf4SFabien Sanglard constexpr Clock::time_point kInvalid = Clock::time_point::min();
16*3f982cf4SFabien Sanglard }
17*3f982cf4SFabien Sanglard 
FakeClock(Clock::time_point start_time)18*3f982cf4SFabien Sanglard FakeClock::FakeClock(Clock::time_point start_time)
19*3f982cf4SFabien Sanglard     : control_thread_id_(std::this_thread::get_id()) {
20*3f982cf4SFabien Sanglard   OSP_CHECK_EQ(now_.load(std::memory_order_acquire), kInvalid)
21*3f982cf4SFabien Sanglard       << "Only one FakeClock instance allowed!";
22*3f982cf4SFabien Sanglard   now_.store(start_time, std::memory_order_release);
23*3f982cf4SFabien Sanglard }
24*3f982cf4SFabien Sanglard 
~FakeClock()25*3f982cf4SFabien Sanglard FakeClock::~FakeClock() {
26*3f982cf4SFabien Sanglard   OSP_CHECK_EQ(std::this_thread::get_id(), control_thread_id_);
27*3f982cf4SFabien Sanglard   OSP_CHECK(task_runners_.empty());
28*3f982cf4SFabien Sanglard   // Set |now_| to kInvalid to flag that this FakeClock has been destroyed.
29*3f982cf4SFabien Sanglard   now_.store(kInvalid, std::memory_order_release);
30*3f982cf4SFabien Sanglard }
31*3f982cf4SFabien Sanglard 
now()32*3f982cf4SFabien Sanglard Clock::time_point FakeClock::now() noexcept {
33*3f982cf4SFabien Sanglard   const Clock::time_point value = now_.load(std::memory_order_acquire);
34*3f982cf4SFabien Sanglard   OSP_CHECK_NE(value, kInvalid) << "No FakeClock instance!";
35*3f982cf4SFabien Sanglard   return value;
36*3f982cf4SFabien Sanglard }
37*3f982cf4SFabien Sanglard 
Advance(Clock::duration delta)38*3f982cf4SFabien Sanglard void FakeClock::Advance(Clock::duration delta) {
39*3f982cf4SFabien Sanglard   OSP_CHECK_EQ(std::this_thread::get_id(), control_thread_id_);
40*3f982cf4SFabien Sanglard 
41*3f982cf4SFabien Sanglard   const Clock::time_point stop_time = now() + delta;
42*3f982cf4SFabien Sanglard 
43*3f982cf4SFabien Sanglard   for (;;) {
44*3f982cf4SFabien Sanglard     // Run tasks at the current time, since this might cause additional delayed
45*3f982cf4SFabien Sanglard     // tasks to be posted.
46*3f982cf4SFabien Sanglard     for (FakeTaskRunner* task_runner : task_runners_) {
47*3f982cf4SFabien Sanglard       task_runner->RunTasksUntilIdle();
48*3f982cf4SFabien Sanglard     }
49*3f982cf4SFabien Sanglard 
50*3f982cf4SFabien Sanglard     // Find the next "step-to" time, and advance the clock to that point.
51*3f982cf4SFabien Sanglard     Clock::time_point step_to = Clock::time_point::max();
52*3f982cf4SFabien Sanglard     for (FakeTaskRunner* task_runner : task_runners_) {
53*3f982cf4SFabien Sanglard       step_to = std::min(step_to, task_runner->GetResumeTime());
54*3f982cf4SFabien Sanglard     }
55*3f982cf4SFabien Sanglard     if (step_to > stop_time) {
56*3f982cf4SFabien Sanglard       break;  // No tasks are scheduled for the remaining time range.
57*3f982cf4SFabien Sanglard     }
58*3f982cf4SFabien Sanglard 
59*3f982cf4SFabien Sanglard     OSP_DCHECK_GT(step_to, now());
60*3f982cf4SFabien Sanglard     now_.store(step_to, std::memory_order_release);
61*3f982cf4SFabien Sanglard   }
62*3f982cf4SFabien Sanglard 
63*3f982cf4SFabien Sanglard   // Skip over any remaining "dead time."
64*3f982cf4SFabien Sanglard   now_.store(stop_time, std::memory_order_release);
65*3f982cf4SFabien Sanglard }
66*3f982cf4SFabien Sanglard 
SubscribeToTimeChanges(FakeTaskRunner * task_runner)67*3f982cf4SFabien Sanglard void FakeClock::SubscribeToTimeChanges(FakeTaskRunner* task_runner) {
68*3f982cf4SFabien Sanglard   OSP_CHECK_EQ(std::this_thread::get_id(), control_thread_id_);
69*3f982cf4SFabien Sanglard   OSP_CHECK(std::find(task_runners_.begin(), task_runners_.end(),
70*3f982cf4SFabien Sanglard                       task_runner) == task_runners_.end());
71*3f982cf4SFabien Sanglard   task_runners_.push_back(task_runner);
72*3f982cf4SFabien Sanglard }
73*3f982cf4SFabien Sanglard 
UnsubscribeFromTimeChanges(FakeTaskRunner * task_runner)74*3f982cf4SFabien Sanglard void FakeClock::UnsubscribeFromTimeChanges(FakeTaskRunner* task_runner) {
75*3f982cf4SFabien Sanglard   OSP_CHECK_EQ(std::this_thread::get_id(), control_thread_id_);
76*3f982cf4SFabien Sanglard   auto it = std::find(task_runners_.begin(), task_runners_.end(), task_runner);
77*3f982cf4SFabien Sanglard   OSP_CHECK(it != task_runners_.end());
78*3f982cf4SFabien Sanglard   task_runners_.erase(it);
79*3f982cf4SFabien Sanglard }
80*3f982cf4SFabien Sanglard 
81*3f982cf4SFabien Sanglard // static
82*3f982cf4SFabien Sanglard std::atomic<Clock::time_point> FakeClock::now_{kInvalid};
83*3f982cf4SFabien Sanglard 
84*3f982cf4SFabien Sanglard }  // namespace openscreen
85