blob: 2fe614faeb1d5f0294ec4e0a109c5663e6c06705 [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 "lib/media/transport/shared_buffer_set.h"
#include <lib/zx/vmo.h>
#include "lib/fxl/logging.h"
namespace media {
SharedBufferSet::SharedBufferSet(uint32_t local_map_flags)
: local_map_flags_(local_map_flags) {}
SharedBufferSet::~SharedBufferSet() {}
zx_status_t SharedBufferSet::AddBuffer(uint32_t buffer_id, zx::vmo vmo) {
if (buffer_id >= buffers_.size()) {
buffers_.resize(buffer_id + 1);
} else {
FXL_DCHECK(!buffers_[buffer_id]);
}
MappedSharedBuffer* mapped_shared_buffer = new MappedSharedBuffer();
zx_status_t status =
mapped_shared_buffer->InitFromVmo(std::move(vmo), local_map_flags_);
if (status == ZX_OK) {
AddBuffer(buffer_id, mapped_shared_buffer);
}
return status;
}
zx_status_t SharedBufferSet::CreateNewBuffer(uint64_t size,
uint32_t* buffer_id_out,
zx_rights_t vmo_rights,
zx::vmo* out_vmo) {
FXL_DCHECK(size != 0);
FXL_DCHECK(buffer_id_out != nullptr);
FXL_DCHECK(out_vmo != nullptr);
uint32_t buffer_id = AllocateBufferId();
MappedSharedBuffer* mapped_shared_buffer = new MappedSharedBuffer();
zx_status_t status = mapped_shared_buffer->InitNew(size, local_map_flags_);
if (status == ZX_OK) {
*buffer_id_out = buffer_id;
*out_vmo = mapped_shared_buffer->GetDuplicateVmo(vmo_rights);
AddBuffer(buffer_id, mapped_shared_buffer);
}
return status;
}
void SharedBufferSet::RemoveBuffer(uint32_t buffer_id) {
FXL_DCHECK(buffer_id < buffers_.size());
FXL_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;
}
FXL_DCHECK(locator.buffer_id() < buffers_.size());
const std::unique_ptr<MappedSharedBuffer>& buffer =
buffers_[locator.buffer_id()];
FXL_DCHECK(buffer);
return buffer->PtrFromOffset(locator.offset());
}
SharedBufferSet::Locator SharedBufferSet::LocatorFromPtr(void* ptr) const {
if (ptr == nullptr) {
return Locator::Null();
}
FXL_DCHECK(!buffer_ids_by_base_address_.empty());
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);
FXL_DCHECK(iter != buffer_ids_by_base_address_.begin());
uint32_t buffer_id = (--iter)->second;
if (!buffers_[buffer_id]) {
return Locator::Null();
}
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