- add sources.
[platform/framework/web/crosswalk.git] / src / net / base / prioritized_dispatcher.cc
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.
4
5 #include "net/base/prioritized_dispatcher.h"
6
7 #include "base/logging.h"
8
9 namespace net {
10
11 PrioritizedDispatcher::Limits::Limits(Priority num_priorities,
12                                       size_t total_jobs)
13     : total_jobs(total_jobs), reserved_slots(num_priorities) {}
14
15 PrioritizedDispatcher::Limits::~Limits() {}
16
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) {
21   SetLimits(limits);
22 }
23
24 PrioritizedDispatcher::~PrioritizedDispatcher() {}
25
26 PrioritizedDispatcher::Handle PrioritizedDispatcher::Add(
27     Job* job, Priority priority) {
28   DCHECK(job);
29   DCHECK_LT(priority, num_priorities());
30   if (num_running_jobs_ < max_running_jobs_[priority]) {
31     ++num_running_jobs_;
32     job->Start();
33     return Handle();
34   }
35   return queue_.Insert(job, priority);
36 }
37
38 PrioritizedDispatcher::Handle PrioritizedDispatcher::AddAtHead(
39     Job* job, Priority priority) {
40   DCHECK(job);
41   DCHECK_LT(priority, num_priorities());
42   if (num_running_jobs_ < max_running_jobs_[priority]) {
43     ++num_running_jobs_;
44     job->Start();
45     return Handle();
46   }
47   return queue_.InsertAtFront(job, priority);
48 }
49
50 void PrioritizedDispatcher::Cancel(const Handle& handle) {
51   queue_.Erase(handle);
52 }
53
54 PrioritizedDispatcher::Job* PrioritizedDispatcher::EvictOldestLowest() {
55   Handle handle = queue_.FirstMin();
56   if (handle.is_null())
57     return NULL;
58   Job* job = handle.value();
59   Cancel(handle);
60   return job;
61 }
62
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.";
69
70   if (handle.priority() == priority)
71     return handle;
72
73   if (MaybeDispatchJob(handle, priority))
74     return Handle();
75   Job* job = handle.value();
76   queue_.Erase(handle);
77   return queue_.Insert(job, priority);
78 }
79
80 void PrioritizedDispatcher::OnJobFinished() {
81   DCHECK_GT(num_running_jobs_, 0u);
82   --num_running_jobs_;
83   MaybeDispatchNextJob();
84 }
85
86 PrioritizedDispatcher::Limits PrioritizedDispatcher::GetLimits() const {
87   size_t num_priorities = max_running_jobs_.size();
88   Limits limits(num_priorities, max_running_jobs_.back());
89
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];
94   }
95
96   return limits;
97 }
98
99 void PrioritizedDispatcher::SetLimits(const Limits& limits) {
100   DCHECK_EQ(queue_.num_priorities(), limits.reserved_slots.size());
101   size_t total = 0;
102   for (size_t i = 0; i < limits.reserved_slots.size(); ++i) {
103     total += limits.reserved_slots[i];
104     max_running_jobs_[i] = total;
105   }
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;
111   }
112
113   // Start pending jobs, if limits permit.
114   while (true) {
115     if (!MaybeDispatchNextJob())
116       break;
117   }
118 }
119
120 void PrioritizedDispatcher::SetLimitsToZero() {
121   SetLimits(Limits(queue_.num_priorities(), 0));
122 }
123
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])
128     return false;
129   Job* job = handle.value();
130   queue_.Erase(handle);
131   ++num_running_jobs_;
132   job->Start();
133   return true;
134 }
135
136 bool PrioritizedDispatcher::MaybeDispatchNextJob() {
137   Handle handle = queue_.FirstMax();
138   if (handle.is_null()) {
139     DCHECK_EQ(0u, queue_.size());
140     return false;
141   }
142   return MaybeDispatchJob(handle, handle.priority());
143 }
144
145 }  // namespace net