mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-28 16:26:10 +03:00
148 lines
4.3 KiB
C++
148 lines
4.3 KiB
C++
|
// Copyright (c) 2012 The Chromium 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 "net/base/prioritized_dispatcher.h"
|
||
|
|
||
|
#include "base/logging.h"
|
||
|
|
||
|
namespace net {
|
||
|
|
||
|
PrioritizedDispatcher::Limits::Limits(Priority num_priorities,
|
||
|
size_t total_jobs)
|
||
|
: total_jobs(total_jobs), reserved_slots(num_priorities) {}
|
||
|
|
||
|
PrioritizedDispatcher::Limits::Limits(const Limits& other) = default;
|
||
|
|
||
|
PrioritizedDispatcher::Limits::~Limits() = default;
|
||
|
|
||
|
PrioritizedDispatcher::PrioritizedDispatcher(const Limits& limits)
|
||
|
: queue_(limits.reserved_slots.size()),
|
||
|
max_running_jobs_(limits.reserved_slots.size()),
|
||
|
num_running_jobs_(0) {
|
||
|
SetLimits(limits);
|
||
|
}
|
||
|
|
||
|
PrioritizedDispatcher::~PrioritizedDispatcher() = default;
|
||
|
|
||
|
PrioritizedDispatcher::Handle PrioritizedDispatcher::Add(
|
||
|
Job* job, Priority priority) {
|
||
|
DCHECK(job);
|
||
|
DCHECK_LT(priority, num_priorities());
|
||
|
if (num_running_jobs_ < max_running_jobs_[priority]) {
|
||
|
++num_running_jobs_;
|
||
|
job->Start();
|
||
|
return Handle();
|
||
|
}
|
||
|
return queue_.Insert(job, priority);
|
||
|
}
|
||
|
|
||
|
PrioritizedDispatcher::Handle PrioritizedDispatcher::AddAtHead(
|
||
|
Job* job, Priority priority) {
|
||
|
DCHECK(job);
|
||
|
DCHECK_LT(priority, num_priorities());
|
||
|
if (num_running_jobs_ < max_running_jobs_[priority]) {
|
||
|
++num_running_jobs_;
|
||
|
job->Start();
|
||
|
return Handle();
|
||
|
}
|
||
|
return queue_.InsertAtFront(job, priority);
|
||
|
}
|
||
|
|
||
|
void PrioritizedDispatcher::Cancel(const Handle& handle) {
|
||
|
queue_.Erase(handle);
|
||
|
}
|
||
|
|
||
|
PrioritizedDispatcher::Job* PrioritizedDispatcher::EvictOldestLowest() {
|
||
|
Handle handle = queue_.FirstMin();
|
||
|
if (handle.is_null())
|
||
|
return NULL;
|
||
|
Job* job = handle.value();
|
||
|
Cancel(handle);
|
||
|
return job;
|
||
|
}
|
||
|
|
||
|
PrioritizedDispatcher::Handle PrioritizedDispatcher::ChangePriority(
|
||
|
const Handle& handle, Priority priority) {
|
||
|
DCHECK(!handle.is_null());
|
||
|
DCHECK_LT(priority, num_priorities());
|
||
|
DCHECK_GE(num_running_jobs_, max_running_jobs_[handle.priority()]) <<
|
||
|
"Job should not be in queue when limits permit it to start.";
|
||
|
|
||
|
if (handle.priority() == priority)
|
||
|
return handle;
|
||
|
|
||
|
if (MaybeDispatchJob(handle, priority))
|
||
|
return Handle();
|
||
|
Job* job = handle.value();
|
||
|
queue_.Erase(handle);
|
||
|
return queue_.Insert(job, priority);
|
||
|
}
|
||
|
|
||
|
void PrioritizedDispatcher::OnJobFinished() {
|
||
|
DCHECK_GT(num_running_jobs_, 0u);
|
||
|
--num_running_jobs_;
|
||
|
MaybeDispatchNextJob();
|
||
|
}
|
||
|
|
||
|
PrioritizedDispatcher::Limits PrioritizedDispatcher::GetLimits() const {
|
||
|
size_t num_priorities = max_running_jobs_.size();
|
||
|
Limits limits(num_priorities, max_running_jobs_.back());
|
||
|
|
||
|
// Calculate the number of jobs reserved for each priority and higher. Leave
|
||
|
// the number of jobs reserved for the lowest priority or higher as 0.
|
||
|
for (size_t i = 1; i < num_priorities; ++i) {
|
||
|
limits.reserved_slots[i] = max_running_jobs_[i] - max_running_jobs_[i - 1];
|
||
|
}
|
||
|
|
||
|
return limits;
|
||
|
}
|
||
|
|
||
|
void PrioritizedDispatcher::SetLimits(const Limits& limits) {
|
||
|
DCHECK_EQ(queue_.num_priorities(), limits.reserved_slots.size());
|
||
|
size_t total = 0;
|
||
|
for (size_t i = 0; i < limits.reserved_slots.size(); ++i) {
|
||
|
total += limits.reserved_slots[i];
|
||
|
max_running_jobs_[i] = total;
|
||
|
}
|
||
|
// Unreserved slots are available for all priorities.
|
||
|
DCHECK_LE(total, limits.total_jobs) << "sum(reserved_slots) <= total_jobs";
|
||
|
size_t spare = limits.total_jobs - total;
|
||
|
for (size_t i = limits.reserved_slots.size(); i > 0; --i) {
|
||
|
max_running_jobs_[i - 1] += spare;
|
||
|
}
|
||
|
|
||
|
// Start pending jobs, if limits permit.
|
||
|
while (true) {
|
||
|
if (!MaybeDispatchNextJob())
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void PrioritizedDispatcher::SetLimitsToZero() {
|
||
|
SetLimits(Limits(queue_.num_priorities(), 0));
|
||
|
}
|
||
|
|
||
|
bool PrioritizedDispatcher::MaybeDispatchJob(const Handle& handle,
|
||
|
Priority job_priority) {
|
||
|
DCHECK_LT(job_priority, num_priorities());
|
||
|
if (num_running_jobs_ >= max_running_jobs_[job_priority])
|
||
|
return false;
|
||
|
Job* job = handle.value();
|
||
|
queue_.Erase(handle);
|
||
|
++num_running_jobs_;
|
||
|
job->Start();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool PrioritizedDispatcher::MaybeDispatchNextJob() {
|
||
|
Handle handle = queue_.FirstMax();
|
||
|
if (handle.is_null()) {
|
||
|
DCHECK_EQ(0u, queue_.size());
|
||
|
return false;
|
||
|
}
|
||
|
return MaybeDispatchJob(handle, handle.priority());
|
||
|
}
|
||
|
|
||
|
} // namespace net
|