| 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..12d097d6145eecf8f846b560e725e25562776b34
|
| --- /dev/null
|
| +++ b/content/browser/loader/resource_scheduler.cc
|
| @@ -0,0 +1,190 @@
|
| +// 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_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(LoadHandleImpl);
|
| +};
|
| +
|
| +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
|
|
|