blob: d66a471b27085ad299e7257ccfa7f3c3609c4508 [file] [log] [blame]
// Copyright 2015 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/child/shared_memory_received_data_factory.h"
#include <algorithm>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "content/common/resource_messages.h"
#include "ipc/ipc_sender.h"
namespace content {
class SharedMemoryReceivedDataFactory::SharedMemoryReceivedData final
: public RequestPeer::ReceivedData {
public:
SharedMemoryReceivedData(
const char* payload,
int length,
scoped_refptr<SharedMemoryReceivedDataFactory> factory,
SharedMemoryReceivedDataFactory::TicketId id)
: payload_(payload),
length_(length),
factory_(factory),
id_(id) {}
~SharedMemoryReceivedData() override { factory_->Reclaim(id_); }
const char* payload() const override { return payload_; }
int length() const override { return length_; }
private:
const char* const payload_;
const int length_;
scoped_refptr<SharedMemoryReceivedDataFactory> factory_;
SharedMemoryReceivedDataFactory::TicketId id_;
DISALLOW_COPY_AND_ASSIGN(SharedMemoryReceivedData);
};
SharedMemoryReceivedDataFactory::SharedMemoryReceivedDataFactory(
IPC::Sender* message_sender,
int request_id,
linked_ptr<base::SharedMemory> memory)
: id_(0),
oldest_(0),
message_sender_(message_sender),
request_id_(request_id),
is_stopped_(false),
memory_(memory) {
}
SharedMemoryReceivedDataFactory::~SharedMemoryReceivedDataFactory() {
if (!is_stopped_)
SendAck(released_tickets_.size());
}
std::unique_ptr<RequestPeer::ReceivedData>
SharedMemoryReceivedDataFactory::Create(int offset, int length) {
const char* start = static_cast<char*>(memory_->memory());
const char* payload = start + offset;
TicketId id = id_++;
return base::MakeUnique<SharedMemoryReceivedData>(payload, length, this, id);
}
void SharedMemoryReceivedDataFactory::Stop() {
is_stopped_ = true;
released_tickets_.clear();
message_sender_ = nullptr;
}
class SharedMemoryReceivedDataFactory::TicketComparator final {
public:
explicit TicketComparator(TicketId oldest) : oldest_(oldest) {}
bool operator()(TicketId x, TicketId y) const {
if ((oldest_ <= x) == (oldest_ <= y))
return x <= y;
return (oldest_ <= x);
}
private:
TicketId oldest_;
};
void SharedMemoryReceivedDataFactory::Reclaim(TicketId id) {
if (is_stopped_)
return;
if (oldest_ != id) {
released_tickets_.push_back(id);
return;
}
++oldest_;
SendAck(1);
if (released_tickets_.empty()) {
// Fast path: (hopefully) the most typical case.
return;
}
std::sort(released_tickets_.begin(), released_tickets_.end(),
TicketComparator(oldest_));
size_t count = 0;
for (size_t i = 0;; ++i) {
if (i == released_tickets_.size() ||
released_tickets_[i] != static_cast<TicketId>(id + i + 1)) {
count = i;
break;
}
}
released_tickets_.erase(released_tickets_.begin(),
released_tickets_.begin() + count);
oldest_ += count;
SendAck(count);
}
void SharedMemoryReceivedDataFactory::SendAck(size_t count) {
for (size_t i = 0; i < count; ++i) {
message_sender_->Send(new ResourceHostMsg_DataReceived_ACK(request_id_));
}
}
} // namespace content