Chromium Code Reviews| Index: content/browser/loader/resource_scheduler.cc |
| diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ef42eaeccd6045700c5f42b25bce50533c4fb7c9 |
| --- /dev/null |
| +++ b/content/browser/loader/resource_scheduler.cc |
| @@ -0,0 +1,188 @@ |
| +// 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 "content/browser/loader/resource_scheduler.h" |
| + |
| +#include "base/stl_util.h" |
| +#include "net/base/load_flags.h" |
| +#include "net/base/request_priority.h" |
| +#include "net/url_request/url_request.h" |
| + |
| +namespace content { |
| + |
| +namespace { |
| + |
| +ResourceScheduler::ClientId MakeClientId(int child_id, int route_id) { |
| + return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
| +} |
| + |
| +} // unnamed namespace |
| + |
| +class LoadHandleImpl : public ResourceScheduler::LoadHandle { |
| + public: |
| + LoadHandleImpl(ResourceScheduler::SchedulerId scheduler_id, |
| + ResourceScheduler::ClientId client_id, |
| + ResourceScheduler* scheduler) |
| + : scheduler_id_(scheduler_id), |
| + client_id_(client_id), |
| + scheduler_(scheduler) { |
| + } |
| + |
| + virtual ~LoadHandleImpl() { |
| + scheduler_->RemoveLoad(scheduler_id_, client_id_); |
| + } |
| + |
| + private: |
| + ResourceScheduler::SchedulerId scheduler_id_; |
| + ResourceScheduler::ClientId client_id_; |
| + ResourceScheduler* scheduler_; |
| +}; |
|
willchan no longer on Chromium
2012/12/13 06:30:43
DISALLOW_COPY_AND_ASSIGN
James Simonsen
2012/12/14 20:23:23
Done.
|
| + |
| +ResourceScheduler::ResourceScheduler() |
| + : next_scheduler_id_(0) { |
| +} |
| + |
| +ResourceScheduler::~ResourceScheduler() { |
| +} |
| + |
| +scoped_ptr<ResourceScheduler::LoadHandle> ResourceScheduler::ScheduleLoad( |
| + int child_id, |
| + int route_id, |
| + Loadable* loadable) { |
| + SchedulerId scheduler_id = ++next_scheduler_id_; |
| + ClientId client_id = MakeClientId(child_id, route_id); |
| + scoped_ptr<LoadHandle> handle(new LoadHandleImpl( |
| + scheduler_id, client_id, this)); |
| + |
| + if (route_id == 0 || !ContainsKey(client_map_, client_id)) { |
| + // <a ping> requests don't belong to a specific page. Most tests don't call |
| + // OnCreate et. al. as needed to register Clients either. |
| + unowned_requests_.insert(scheduler_id); |
| + loadable->StartRequest(); |
| + return handle.Pass(); |
| + } |
| + |
| + Client* client = client_map_[client_id]; |
| + DCHECK(!client->has_closed); |
| + Request request = { scheduler_id, loadable }; |
| + |
| + // Treat synchronous requests as high priority. |
| + bool is_low_priority = loadable->url_request()->priority() < net::MEDIUM && |
| + !(loadable->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS); |
| + |
| + if (is_low_priority && !client->in_flight_requests.empty() && |
| + !client->has_painted) { |
| + client->pending_requests.push_back(request); |
| + } else { |
| + StartRequest(request, client); |
| + } |
| + return handle.Pass(); |
| +} |
| + |
| +void ResourceScheduler::RemoveLoad(SchedulerId scheduler_id, |
| + ClientId client_id) { |
| + if (ContainsKey(unowned_requests_, scheduler_id)) { |
| + unowned_requests_.erase(scheduler_id); |
| + return; |
| + } |
| + |
| + DCHECK(ContainsKey(client_map_, client_id)); |
| + Client* client = client_map_[client_id]; |
| + SchedulerIdSet::iterator it = client->in_flight_requests.find(scheduler_id); |
| + if (it == client->in_flight_requests.end()) { |
| + bool removed = false; |
| + RequestQueue::iterator queue_it; |
| + for (queue_it = client->pending_requests.begin(); |
| + queue_it != client->pending_requests.end(); ++queue_it) { |
| + if (queue_it->scheduler_id == scheduler_id) { |
| + client->pending_requests.erase(queue_it); |
| + removed = true; |
| + break; |
| + } |
| + } |
| + DCHECK(removed); |
| + DCHECK(!ContainsKey(client->in_flight_requests, scheduler_id)); |
| + } else { |
| + size_t erased = client->in_flight_requests.erase(scheduler_id); |
| + DCHECK(erased); |
| + } |
| + |
| + if (client->has_closed) { |
| + if (client->in_flight_requests.empty() |
| + && client->pending_requests.empty()) { |
| + delete client; |
| + client_map_.erase(client_id); |
| + } |
| + } else if (client->in_flight_requests.empty()) { |
| + LoadPendingRequests(client); |
| + } |
| +} |
| + |
| +void ResourceScheduler::OnCreate(int child_id, int route_id) { |
| + ClientId client_id = MakeClientId(child_id, route_id); |
| + DCHECK(!ContainsKey(client_map_, client_id)); |
| + client_map_[client_id] = new Client; |
| +} |
| + |
| +void ResourceScheduler::OnNavigate(int child_id, int route_id) { |
| + ClientId client_id = MakeClientId(child_id, route_id); |
| + if (!ContainsKey(client_map_, client_id)) { |
| + return; |
| + } |
| + |
| + Client* client = client_map_[client_id]; |
| + client->has_painted = false; |
| +} |
| + |
| +void ResourceScheduler::OnPaint(int child_id, int route_id) { |
| + ClientId client_id = MakeClientId(child_id, route_id); |
| + if (!ContainsKey(client_map_, client_id)) { |
| + return; |
| + } |
| + |
| + Client* client = client_map_[client_id]; |
| + if (!client->has_painted) { |
| + client->has_painted = true; |
| + LoadPendingRequests(client); |
| + } |
| +} |
| + |
| +void ResourceScheduler::OnDestroy(int child_id, int route_id) { |
| + ClientId client_id = MakeClientId(child_id, route_id); |
| + if (!ContainsKey(client_map_, client_id)) { |
| + return; |
| + } |
| + |
| + Client* client = client_map_[client_id]; |
| + if (client->pending_requests.empty() && client->in_flight_requests.empty()) { |
| + delete client; |
| + client_map_.erase(client_id); |
| + } else { |
| + client->has_closed = true; |
| + } |
| +} |
| + |
| +void ResourceScheduler::StartRequest(Request request, Client* client) { |
| + client->in_flight_requests.insert(request.scheduler_id); |
| + request.loadable->StartRequest(); |
| +} |
| + |
| +void ResourceScheduler::LoadPendingRequests(Client* client) { |
| + RequestQueue::iterator it; |
| + for (it = client->pending_requests.begin(); |
| + it != client->pending_requests.end(); ++it) { |
| + StartRequest(*it, client); |
| + } |
| + client->pending_requests.clear(); |
| +} |
| + |
| +ResourceScheduler::Client::Client() |
| + : has_painted(false), |
| + has_closed(false) { |
| +} |
| + |
| +ResourceScheduler::Client::~Client() { |
| +} |
| + |
| +} // namespace content |