blob: dd47756236a649b743fae6604d5ce9c4ff351e05 [file] [log] [blame]
// Copyright 2016 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 "mojo/services/media/common/cpp/shared_buffer_set.h"
#include "mojo/public/cpp/environment/logging.h"
#include "mojo/public/cpp/system/handle.h"
namespace mojo {
namespace media {
SharedBufferSet::SharedBufferSet() {}
SharedBufferSet::~SharedBufferSet() {}
MojoResult SharedBufferSet::AddBuffer(uint32_t buffer_id,
ScopedSharedBufferHandle handle) {
if (buffer_id >= buffers_.size()) {
buffers_.resize(buffer_id + 1);
} else {
MOJO_DCHECK(!buffers_[buffer_id]);
}
MappedSharedBuffer* mapped_shared_buffer = new MappedSharedBuffer();
MojoResult result = mapped_shared_buffer->InitFromHandle(handle.Pass());
if (result == MOJO_RESULT_OK) {
AddBuffer(buffer_id, mapped_shared_buffer);
}
return result;
}
MojoResult SharedBufferSet::CreateNewBuffer(
uint64_t size,
uint32_t* buffer_id_out,
ScopedSharedBufferHandle* handle_out) {
MOJO_DCHECK(size != 0);
MOJO_DCHECK(buffer_id_out != nullptr);
MOJO_DCHECK(handle_out != nullptr);
uint32_t buffer_id = AllocateBufferId();
MappedSharedBuffer* mapped_shared_buffer = new MappedSharedBuffer();
MojoResult result = mapped_shared_buffer->InitNew(size);
if (result == MOJO_RESULT_OK) {
*buffer_id_out = buffer_id;
*handle_out = mapped_shared_buffer->GetDuplicateHandle();
AddBuffer(buffer_id, mapped_shared_buffer);
}
return result;
}
void SharedBufferSet::RemoveBuffer(uint32_t buffer_id) {
MOJO_DCHECK(buffer_id < buffers_.size());
MOJO_DCHECK(buffers_[buffer_id]);
buffer_ids_by_base_address_.erase(
reinterpret_cast<uint8_t*>(buffers_[buffer_id]->PtrFromOffset(0)));
buffers_[buffer_id].reset();
}
void SharedBufferSet::Reset() {
buffers_.clear();
buffer_ids_by_base_address_.clear();
}
bool SharedBufferSet::Validate(const Locator& locator, uint64_t size) const {
if (!locator || locator.buffer_id() >= buffers_.size()) {
return false;
}
const std::unique_ptr<MappedSharedBuffer>& buffer =
buffers_[locator.buffer_id()];
if (!buffer) {
return false;
}
return buffer->Validate(locator.offset(), size);
}
void* SharedBufferSet::PtrFromLocator(const Locator& locator) const {
if (!locator) {
return nullptr;
}
MOJO_DCHECK(locator.buffer_id() < buffers_.size());
const std::unique_ptr<MappedSharedBuffer>& buffer =
buffers_[locator.buffer_id()];
MOJO_DCHECK(buffer);
return buffer->PtrFromOffset(locator.offset());
}
SharedBufferSet::Locator SharedBufferSet::LocatorFromPtr(void* ptr) const {
MOJO_DCHECK(!buffer_ids_by_base_address_.empty());
if (ptr == nullptr) {
return Locator::Null();
}
uint8_t* byte_ptr = reinterpret_cast<uint8_t*>(ptr);
// upper_bound finds the first buffer whose base address is greater than the
// supplied pointer. We want the buffer just before that. If upper_bound()
// returns begin(), the pointer is less than any of the base addresses and
// isn't valid.
auto iter = buffer_ids_by_base_address_.upper_bound(byte_ptr);
MOJO_DCHECK(iter != buffer_ids_by_base_address_.begin());
uint32_t buffer_id = (--iter)->second;
MOJO_DCHECK(buffers_[buffer_id]);
return Locator(buffer_id, buffers_[buffer_id]->OffsetFromPtr(byte_ptr));
}
uint32_t SharedBufferSet::AllocateBufferId() {
uint32_t buffer_id = 0;
for (const std::unique_ptr<MappedSharedBuffer>& buffer : buffers_) {
if (!buffer) {
return buffer_id;
}
++buffer_id;
}
buffers_.resize(buffer_id + 1);
return buffer_id;
}
void SharedBufferSet::AddBuffer(uint32_t buffer_id,
MappedSharedBuffer* mapped_shared_buffer) {
buffer_ids_by_base_address_.insert(std::make_pair(
reinterpret_cast<uint8_t*>(mapped_shared_buffer->PtrFromOffset(0)),
buffer_id));
buffers_[buffer_id].reset(mapped_shared_buffer);
}
} // namespace media
} // namespace mojo