// 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 #include #include #include 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& 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 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(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