xref: /aosp_15_r20/external/cronet/net/base/prioritized_dispatcher.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/base/prioritized_dispatcher.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <ostream>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker namespace net {
12*6777b538SAndroid Build Coastguard Worker 
Limits(Priority num_priorities,size_t total_jobs)13*6777b538SAndroid Build Coastguard Worker PrioritizedDispatcher::Limits::Limits(Priority num_priorities,
14*6777b538SAndroid Build Coastguard Worker                                       size_t total_jobs)
15*6777b538SAndroid Build Coastguard Worker     : total_jobs(total_jobs), reserved_slots(num_priorities) {}
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker PrioritizedDispatcher::Limits::Limits(const Limits& other) = default;
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker PrioritizedDispatcher::Limits::~Limits() = default;
20*6777b538SAndroid Build Coastguard Worker 
PrioritizedDispatcher(const Limits & limits)21*6777b538SAndroid Build Coastguard Worker PrioritizedDispatcher::PrioritizedDispatcher(const Limits& limits)
22*6777b538SAndroid Build Coastguard Worker     : queue_(limits.reserved_slots.size()),
23*6777b538SAndroid Build Coastguard Worker       max_running_jobs_(limits.reserved_slots.size()) {
24*6777b538SAndroid Build Coastguard Worker   SetLimits(limits);
25*6777b538SAndroid Build Coastguard Worker }
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker PrioritizedDispatcher::~PrioritizedDispatcher() = default;
28*6777b538SAndroid Build Coastguard Worker 
Add(Job * job,Priority priority)29*6777b538SAndroid Build Coastguard Worker PrioritizedDispatcher::Handle PrioritizedDispatcher::Add(
30*6777b538SAndroid Build Coastguard Worker     Job* job, Priority priority) {
31*6777b538SAndroid Build Coastguard Worker   DCHECK(job);
32*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(priority, num_priorities());
33*6777b538SAndroid Build Coastguard Worker   if (num_running_jobs_ < max_running_jobs_[priority]) {
34*6777b538SAndroid Build Coastguard Worker     ++num_running_jobs_;
35*6777b538SAndroid Build Coastguard Worker     job->Start();
36*6777b538SAndroid Build Coastguard Worker     return Handle();
37*6777b538SAndroid Build Coastguard Worker   }
38*6777b538SAndroid Build Coastguard Worker   return queue_.Insert(job, priority);
39*6777b538SAndroid Build Coastguard Worker }
40*6777b538SAndroid Build Coastguard Worker 
AddAtHead(Job * job,Priority priority)41*6777b538SAndroid Build Coastguard Worker PrioritizedDispatcher::Handle PrioritizedDispatcher::AddAtHead(
42*6777b538SAndroid Build Coastguard Worker     Job* job, Priority priority) {
43*6777b538SAndroid Build Coastguard Worker   DCHECK(job);
44*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(priority, num_priorities());
45*6777b538SAndroid Build Coastguard Worker   if (num_running_jobs_ < max_running_jobs_[priority]) {
46*6777b538SAndroid Build Coastguard Worker     ++num_running_jobs_;
47*6777b538SAndroid Build Coastguard Worker     job->Start();
48*6777b538SAndroid Build Coastguard Worker     return Handle();
49*6777b538SAndroid Build Coastguard Worker   }
50*6777b538SAndroid Build Coastguard Worker   return queue_.InsertAtFront(job, priority);
51*6777b538SAndroid Build Coastguard Worker }
52*6777b538SAndroid Build Coastguard Worker 
Cancel(const Handle & handle)53*6777b538SAndroid Build Coastguard Worker void PrioritizedDispatcher::Cancel(const Handle& handle) {
54*6777b538SAndroid Build Coastguard Worker   queue_.Erase(handle);
55*6777b538SAndroid Build Coastguard Worker }
56*6777b538SAndroid Build Coastguard Worker 
EvictOldestLowest()57*6777b538SAndroid Build Coastguard Worker PrioritizedDispatcher::Job* PrioritizedDispatcher::EvictOldestLowest() {
58*6777b538SAndroid Build Coastguard Worker   Handle handle = queue_.FirstMin();
59*6777b538SAndroid Build Coastguard Worker   if (handle.is_null())
60*6777b538SAndroid Build Coastguard Worker     return nullptr;
61*6777b538SAndroid Build Coastguard Worker   Job* job = handle.value();
62*6777b538SAndroid Build Coastguard Worker   Cancel(handle);
63*6777b538SAndroid Build Coastguard Worker   return job;
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker 
ChangePriority(const Handle & handle,Priority priority)66*6777b538SAndroid Build Coastguard Worker PrioritizedDispatcher::Handle PrioritizedDispatcher::ChangePriority(
67*6777b538SAndroid Build Coastguard Worker     const Handle& handle, Priority priority) {
68*6777b538SAndroid Build Coastguard Worker   DCHECK(!handle.is_null());
69*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(priority, num_priorities());
70*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(num_running_jobs_, max_running_jobs_[handle.priority()]) <<
71*6777b538SAndroid Build Coastguard Worker       "Job should not be in queue when limits permit it to start.";
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker   if (handle.priority() == priority)
74*6777b538SAndroid Build Coastguard Worker     return handle;
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   if (MaybeDispatchJob(handle, priority))
77*6777b538SAndroid Build Coastguard Worker     return Handle();
78*6777b538SAndroid Build Coastguard Worker   Job* job = handle.value();
79*6777b538SAndroid Build Coastguard Worker   queue_.Erase(handle);
80*6777b538SAndroid Build Coastguard Worker   return queue_.Insert(job, priority);
81*6777b538SAndroid Build Coastguard Worker }
82*6777b538SAndroid Build Coastguard Worker 
OnJobFinished()83*6777b538SAndroid Build Coastguard Worker void PrioritizedDispatcher::OnJobFinished() {
84*6777b538SAndroid Build Coastguard Worker   DCHECK_GT(num_running_jobs_, 0u);
85*6777b538SAndroid Build Coastguard Worker   --num_running_jobs_;
86*6777b538SAndroid Build Coastguard Worker   MaybeDispatchNextJob();
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker 
GetLimits() const89*6777b538SAndroid Build Coastguard Worker PrioritizedDispatcher::Limits PrioritizedDispatcher::GetLimits() const {
90*6777b538SAndroid Build Coastguard Worker   size_t num_priorities = max_running_jobs_.size();
91*6777b538SAndroid Build Coastguard Worker   Limits limits(num_priorities, max_running_jobs_.back());
92*6777b538SAndroid Build Coastguard Worker 
93*6777b538SAndroid Build Coastguard Worker   // Calculate the number of jobs reserved for each priority and higher.  Leave
94*6777b538SAndroid Build Coastguard Worker   // the number of jobs reserved for the lowest priority or higher as 0.
95*6777b538SAndroid Build Coastguard Worker   for (size_t i = 1; i < num_priorities; ++i) {
96*6777b538SAndroid Build Coastguard Worker     limits.reserved_slots[i] = max_running_jobs_[i] - max_running_jobs_[i - 1];
97*6777b538SAndroid Build Coastguard Worker   }
98*6777b538SAndroid Build Coastguard Worker 
99*6777b538SAndroid Build Coastguard Worker   return limits;
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker 
SetLimits(const Limits & limits)102*6777b538SAndroid Build Coastguard Worker void PrioritizedDispatcher::SetLimits(const Limits& limits) {
103*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(queue_.num_priorities(), limits.reserved_slots.size());
104*6777b538SAndroid Build Coastguard Worker   size_t total = 0;
105*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < limits.reserved_slots.size(); ++i) {
106*6777b538SAndroid Build Coastguard Worker     total += limits.reserved_slots[i];
107*6777b538SAndroid Build Coastguard Worker     max_running_jobs_[i] = total;
108*6777b538SAndroid Build Coastguard Worker   }
109*6777b538SAndroid Build Coastguard Worker   // Unreserved slots are available for all priorities.
110*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(total, limits.total_jobs) << "sum(reserved_slots) <= total_jobs";
111*6777b538SAndroid Build Coastguard Worker   size_t spare = limits.total_jobs - total;
112*6777b538SAndroid Build Coastguard Worker   for (size_t i = limits.reserved_slots.size(); i > 0; --i) {
113*6777b538SAndroid Build Coastguard Worker     max_running_jobs_[i - 1] += spare;
114*6777b538SAndroid Build Coastguard Worker   }
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker   // Start pending jobs, if limits permit.
117*6777b538SAndroid Build Coastguard Worker   while (true) {
118*6777b538SAndroid Build Coastguard Worker     if (!MaybeDispatchNextJob())
119*6777b538SAndroid Build Coastguard Worker       break;
120*6777b538SAndroid Build Coastguard Worker   }
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker 
SetLimitsToZero()123*6777b538SAndroid Build Coastguard Worker void PrioritizedDispatcher::SetLimitsToZero() {
124*6777b538SAndroid Build Coastguard Worker   SetLimits(Limits(queue_.num_priorities(), 0));
125*6777b538SAndroid Build Coastguard Worker }
126*6777b538SAndroid Build Coastguard Worker 
MaybeDispatchJob(const Handle & handle,Priority job_priority)127*6777b538SAndroid Build Coastguard Worker bool PrioritizedDispatcher::MaybeDispatchJob(const Handle& handle,
128*6777b538SAndroid Build Coastguard Worker                                              Priority job_priority) {
129*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(job_priority, num_priorities());
130*6777b538SAndroid Build Coastguard Worker   if (num_running_jobs_ >= max_running_jobs_[job_priority])
131*6777b538SAndroid Build Coastguard Worker     return false;
132*6777b538SAndroid Build Coastguard Worker   Job* job = handle.value();
133*6777b538SAndroid Build Coastguard Worker   queue_.Erase(handle);
134*6777b538SAndroid Build Coastguard Worker   ++num_running_jobs_;
135*6777b538SAndroid Build Coastguard Worker   job->Start();
136*6777b538SAndroid Build Coastguard Worker   return true;
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker 
MaybeDispatchNextJob()139*6777b538SAndroid Build Coastguard Worker bool PrioritizedDispatcher::MaybeDispatchNextJob() {
140*6777b538SAndroid Build Coastguard Worker   Handle handle = queue_.FirstMax();
141*6777b538SAndroid Build Coastguard Worker   if (handle.is_null()) {
142*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(0u, queue_.size());
143*6777b538SAndroid Build Coastguard Worker     return false;
144*6777b538SAndroid Build Coastguard Worker   }
145*6777b538SAndroid Build Coastguard Worker   return MaybeDispatchJob(handle, handle.priority());
146*6777b538SAndroid Build Coastguard Worker }
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker }  // namespace net
149