blob: 05245c572a51b550aa6fa2d692c8549067163b6e [file] [log] [blame]
// Copyright 2018 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/fzl/vmo-pool.h>
#include <lib/zx/vmar.h>
#include <string.h>
#include <utility>
namespace fzl {
VmoPool::~VmoPool() {
// Clear out the free_buffers_, since the intrusive container
// will throw an assert if it contains unmanaged pointers on
// destruction.
free_buffers_.clear_unsafe();
}
zx_status_t VmoPool::Init(const fbl::Vector<zx::vmo>& vmos) {
return Init(vmos.begin(), vmos.size());
}
zx_status_t VmoPool::Init(const zx::vmo* vmos, size_t num_vmos) {
fbl::AllocChecker ac;
fbl::Array<ListableBuffer> buffers(new (&ac) ListableBuffer[num_vmos], num_vmos);
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
buffers_ = std::move(buffers);
free_buffers_.clear_unsafe();
zx_status_t status;
for (size_t i = 0; i < num_vmos; ++i) {
free_buffers_.push_front(&buffers_[i]);
status = buffers_[i].buffer.Map(vmos[i], 0, 0, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE);
if (status != ZX_OK) {
free_buffers_.clear_unsafe();
buffers_.reset();
return status;
}
}
current_buffer_ = kInvalidCurBuffer;
return ZX_OK;
}
void VmoPool::Reset() {
current_buffer_ = kInvalidCurBuffer;
for (size_t i = 0; i < buffers_.size(); ++i) {
if (!buffers_[i].InContainer()) {
free_buffers_.push_front(&buffers_[i]);
}
}
}
zx_status_t VmoPool::GetNewBuffer(uint32_t* buffer_index) {
if (HasBufferInProgress()) {
return ZX_ERR_BAD_STATE;
}
if (free_buffers_.is_empty()) { // No available buffers!
return ZX_ERR_NOT_FOUND;
}
ListableBuffer* buf = free_buffers_.pop_front();
ZX_DEBUG_ASSERT(buf >= &buffers_[0]);
uint32_t buffer_offset = static_cast<uint32_t>(buf - &buffers_[0]);
ZX_DEBUG_ASSERT(buffer_offset < buffers_.size());
current_buffer_ = buffer_offset;
if (buffer_index != nullptr) {
*buffer_index = current_buffer_;
}
return ZX_OK;
}
zx_status_t VmoPool::BufferCompleted(uint32_t* buffer_index) {
if (!HasBufferInProgress()) {
return ZX_ERR_BAD_STATE;
}
if (buffer_index != nullptr) {
*buffer_index = current_buffer_;
}
current_buffer_ = kInvalidCurBuffer;
return ZX_OK;
}
zx_status_t VmoPool::BufferRelease(uint32_t buffer_index) {
if (buffer_index >= buffers_.size()) {
return ZX_ERR_INVALID_ARGS;
}
if (buffers_[buffer_index].InContainer()) {
return ZX_ERR_NOT_FOUND;
}
// If we are cancelling the in-progress buffer:
if (current_buffer_ == buffer_index) {
current_buffer_ = kInvalidCurBuffer;
}
free_buffers_.push_front(&buffers_[buffer_index]);
return ZX_OK;
}
uint64_t VmoPool::CurrentBufferSize() const {
if (HasBufferInProgress()) {
return buffers_[current_buffer_].buffer.size();
}
return 0;
}
void* VmoPool::CurrentBufferAddress() const {
if (HasBufferInProgress()) {
return buffers_[current_buffer_].buffer.start();
}
return nullptr;
}
} // namespace fzl