1 // Copyright (c) 2012 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.
5 #include "net/base/prioritized_dispatcher.h"
7 #include "base/logging.h"
11 PrioritizedDispatcher::Limits::Limits(Priority num_priorities
,
13 : total_jobs(total_jobs
), reserved_slots(num_priorities
) {}
15 PrioritizedDispatcher::Limits::~Limits() {}
17 PrioritizedDispatcher::PrioritizedDispatcher(const Limits
& limits
)
18 : queue_(limits
.reserved_slots
.size()),
19 max_running_jobs_(limits
.reserved_slots
.size()),
20 num_running_jobs_(0) {
24 PrioritizedDispatcher::~PrioritizedDispatcher() {}
26 PrioritizedDispatcher::Handle
PrioritizedDispatcher::Add(
27 Job
* job
, Priority priority
) {
29 DCHECK_LT(priority
, num_priorities());
30 if (num_running_jobs_
< max_running_jobs_
[priority
]) {
35 return queue_
.Insert(job
, priority
);
38 PrioritizedDispatcher::Handle
PrioritizedDispatcher::AddAtHead(
39 Job
* job
, Priority priority
) {
41 DCHECK_LT(priority
, num_priorities());
42 if (num_running_jobs_
< max_running_jobs_
[priority
]) {
47 return queue_
.InsertAtFront(job
, priority
);
50 void PrioritizedDispatcher::Cancel(const Handle
& handle
) {
54 PrioritizedDispatcher::Job
* PrioritizedDispatcher::EvictOldestLowest() {
55 Handle handle
= queue_
.FirstMin();
58 Job
* job
= handle
.value();
63 PrioritizedDispatcher::Handle
PrioritizedDispatcher::ChangePriority(
64 const Handle
& handle
, Priority priority
) {
65 DCHECK(!handle
.is_null());
66 DCHECK_LT(priority
, num_priorities());
67 DCHECK_GE(num_running_jobs_
, max_running_jobs_
[handle
.priority()]) <<
68 "Job should not be in queue when limits permit it to start.";
70 if (handle
.priority() == priority
)
73 if (MaybeDispatchJob(handle
, priority
))
75 Job
* job
= handle
.value();
77 return queue_
.Insert(job
, priority
);
80 void PrioritizedDispatcher::OnJobFinished() {
81 DCHECK_GT(num_running_jobs_
, 0u);
83 MaybeDispatchNextJob();
86 PrioritizedDispatcher::Limits
PrioritizedDispatcher::GetLimits() const {
87 size_t num_priorities
= max_running_jobs_
.size();
88 Limits
limits(num_priorities
, max_running_jobs_
.back());
90 // Calculate the number of jobs reserved for each priority and higher. Leave
91 // the number of jobs reserved for the lowest priority or higher as 0.
92 for (size_t i
= 1; i
< num_priorities
; ++i
) {
93 limits
.reserved_slots
[i
] = max_running_jobs_
[i
] - max_running_jobs_
[i
- 1];
99 void PrioritizedDispatcher::SetLimits(const Limits
& limits
) {
100 DCHECK_EQ(queue_
.num_priorities(), limits
.reserved_slots
.size());
102 for (size_t i
= 0; i
< limits
.reserved_slots
.size(); ++i
) {
103 total
+= limits
.reserved_slots
[i
];
104 max_running_jobs_
[i
] = total
;
106 // Unreserved slots are available for all priorities.
107 DCHECK_LE(total
, limits
.total_jobs
) << "sum(reserved_slots) <= total_jobs";
108 size_t spare
= limits
.total_jobs
- total
;
109 for (size_t i
= limits
.reserved_slots
.size(); i
> 0; --i
) {
110 max_running_jobs_
[i
- 1] += spare
;
113 // Start pending jobs, if limits permit.
115 if (!MaybeDispatchNextJob())
120 void PrioritizedDispatcher::SetLimitsToZero() {
121 SetLimits(Limits(queue_
.num_priorities(), 0));
124 bool PrioritizedDispatcher::MaybeDispatchJob(const Handle
& handle
,
125 Priority job_priority
) {
126 DCHECK_LT(job_priority
, num_priorities());
127 if (num_running_jobs_
>= max_running_jobs_
[job_priority
])
129 Job
* job
= handle
.value();
130 queue_
.Erase(handle
);
136 bool PrioritizedDispatcher::MaybeDispatchNextJob() {
137 Handle handle
= queue_
.FirstMax();
138 if (handle
.is_null()) {
139 DCHECK_EQ(0u, queue_
.size());
142 return MaybeDispatchJob(handle
, handle
.priority());