blob: b1f990f6cf165cf33cd208a8ec082aac26b1fc19 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "garnet/lib/overnet/testing/test_timer.h"
#include <mutex>
namespace overnet {
static std::mutex mu;
TestTimer::~TestTimer() {
shutting_down_ = true;
for (auto tmr : pending_timeouts_) {
assert(tmr.first > now_);
FireTimeout(tmr.second, Status::Cancelled());
}
}
TimeStamp TestTimer::Now() {
std::lock_guard<std::mutex> lock(mu);
if (shutting_down_)
return TimeStamp::AfterEpoch(TimeDelta::PositiveInf());
return TimeStamp::AfterEpoch(TimeDelta::FromMicroseconds(now_));
}
bool TestTimer::Step(uint64_t microseconds) {
{
std::lock_guard<std::mutex> lock(mu);
if (shutting_down_)
return false;
auto new_now = now_ + microseconds;
if (now_ > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
return false;
}
if (TimeStamp::AfterEpoch(TimeDelta::FromMicroseconds(new_now)) <
TimeStamp::AfterEpoch(TimeDelta::FromMicroseconds(now_))) {
return false;
}
now_ = new_now;
}
bool ticked = false;
while (!pending_timeouts_.empty() &&
pending_timeouts_.begin()->first <=
(std::lock_guard<std::mutex>(mu), now_)) {
ticked = true;
auto it = pending_timeouts_.begin();
auto* timeout = it->second;
pending_timeouts_.erase(it);
FireTimeout(timeout, Status::Ok());
}
return ticked;
}
bool TestTimer::StepUntilNextEvent(Optional<TimeDelta> max_step) {
if (pending_timeouts_.empty())
return false;
int64_t step = (std::lock_guard<std::mutex>(mu),
pending_timeouts_.begin()->first - now_);
if (max_step.has_value() && step > max_step->as_us()) {
step = max_step->as_us();
}
return Step(step);
}
void TestTimer::InitTimeout(Timeout* timeout, TimeStamp when) {
if (shutting_down_) {
FireTimeout(timeout, Status::Cancelled());
return;
}
*TimeoutStorage<uint64_t>(timeout) = when.after_epoch().as_us();
pending_timeouts_.emplace(when.after_epoch().as_us(), timeout);
}
void TestTimer::CancelTimeout(Timeout* timeout, Status status) {
assert(!status.is_ok());
auto rng = pending_timeouts_.equal_range(*TimeoutStorage<uint64_t>(timeout));
for (auto it = rng.first; it != rng.second; ++it) {
if (it->second == timeout) {
pending_timeouts_.erase(it);
break;
}
}
FireTimeout(timeout, status);
}
} // namespace overnet