blob: 660e632830b1bd93c7d7e5cfe8e4ada627f8314e [file] [log] [blame] [edit]
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "shill/network/trial_scheduler.h"
#include <algorithm>
#include <utility>
#include <base/functional/bind.h>
#include <base/functional/callback.h>
#include <base/logging.h>
#include <base/memory/weak_ptr.h>
#include <base/time/time.h>
#include "shill/event_dispatcher.h"
namespace shill {
TrialScheduler::TrialScheduler(EventDispatcher* dispatcher)
: dispatcher_(dispatcher) {}
TrialScheduler::~TrialScheduler() = default;
bool TrialScheduler::ScheduleTrial(base::OnceClosure trial) {
if (IsTrialScheduled()) {
LOG(WARNING) << "The previous scheduled trial hasn't been executed yet";
return false;
}
trial_ = std::move(trial);
dispatcher_->PostDelayedTask(FROM_HERE,
base::BindOnce(&TrialScheduler::ExecuteTrial,
weak_ptr_factory_.GetWeakPtr()),
GetNextTrialDelay());
return true;
}
void TrialScheduler::ExecuteTrial() {
if (!trial_.is_null()) {
UpdateNextInterval();
last_trial_start_time_ = base::TimeTicks::Now();
std::move(trial_).Run();
}
}
void TrialScheduler::CancelTrial() {
trial_.Reset();
weak_ptr_factory_.InvalidateWeakPtrs();
}
bool TrialScheduler::IsTrialScheduled() const {
return !trial_.is_null();
}
void TrialScheduler::ResetInterval() {
next_interval_ = base::TimeDelta();
}
void TrialScheduler::UpdateNextInterval() {
if (next_interval_.is_zero()) {
next_interval_ = kBaseInterval;
} else if (next_interval_ < kMaxInterval) {
next_interval_ = std::min(next_interval_ * 2, kMaxInterval);
}
}
base::TimeDelta TrialScheduler::GetNextTrialDelay() const {
if (next_interval_.is_zero()) {
return base::TimeDelta();
}
const base::TimeTicks next_attempt = last_trial_start_time_ + next_interval_;
return std::max(next_attempt - base::TimeTicks::Now(), kMinDelay);
}
} // namespace shill