1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <lib/fzl/vmo-pool.h> 6#include <lib/zx/vmar.h> 7#include <string.h> 8 9namespace fzl { 10 11VmoPool::~VmoPool() { 12 // Clear out the free_buffers_, since the intrusive container 13 // will throw an assert if it contains unmanaged pointers on 14 // destruction. 15 free_buffers_.clear_unsafe(); 16} 17 18zx_status_t VmoPool::Init(const fbl::Vector<zx::vmo>& vmos) { 19 return Init(vmos.begin(), vmos.size()); 20} 21 22zx_status_t VmoPool::Init(const zx::vmo* vmos, size_t num_vmos) { 23 fbl::AllocChecker ac; 24 fbl::Array<ListableBuffer> buffers(new (&ac) ListableBuffer[num_vmos], num_vmos); 25 if (!ac.check()) { 26 return ZX_ERR_NO_MEMORY; 27 } 28 buffers_ = fbl::move(buffers); 29 free_buffers_.clear_unsafe(); 30 31 zx_status_t status; 32 for (size_t i = 0; i < num_vmos; ++i) { 33 free_buffers_.push_front(&buffers_[i]); 34 status = buffers_[i].buffer.Map(vmos[i], 0, 0, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE); 35 if (status != ZX_OK) { 36 free_buffers_.clear_unsafe(); 37 buffers_.reset(); 38 return status; 39 } 40 } 41 current_buffer_ = kInvalidCurBuffer; 42 return ZX_OK; 43} 44 45void VmoPool::Reset() { 46 current_buffer_ = kInvalidCurBuffer; 47 for (size_t i = 0; i < buffers_.size(); ++i) { 48 if (!buffers_[i].InContainer()) { 49 free_buffers_.push_front(&buffers_[i]); 50 } 51 } 52} 53 54zx_status_t VmoPool::GetNewBuffer(uint32_t* buffer_index) { 55 if (HasBufferInProgress()) { 56 return ZX_ERR_BAD_STATE; 57 } 58 if (free_buffers_.is_empty()) { // No available buffers! 59 return ZX_ERR_NOT_FOUND; 60 } 61 ListableBuffer* buf = free_buffers_.pop_front(); 62 ZX_DEBUG_ASSERT(buf >= &buffers_[0]); 63 uint32_t buffer_offset = static_cast<uint32_t>(buf - &buffers_[0]); 64 ZX_DEBUG_ASSERT(buffer_offset < buffers_.size()); 65 current_buffer_ = buffer_offset; 66 if (buffer_index != nullptr) { 67 *buffer_index = current_buffer_; 68 } 69 return ZX_OK; 70} 71 72zx_status_t VmoPool::BufferCompleted(uint32_t* buffer_index) { 73 if (!HasBufferInProgress()) { 74 return ZX_ERR_BAD_STATE; 75 } 76 if (buffer_index != nullptr) { 77 *buffer_index = current_buffer_; 78 } 79 current_buffer_ = kInvalidCurBuffer; 80 return ZX_OK; 81} 82 83zx_status_t VmoPool::BufferRelease(uint32_t buffer_index) { 84 if (buffer_index >= buffers_.size()) { 85 return ZX_ERR_INVALID_ARGS; 86 } 87 if (buffers_[buffer_index].InContainer()) { 88 return ZX_ERR_NOT_FOUND; 89 } 90 // If we are cancelling the in-progress buffer: 91 if (current_buffer_ == buffer_index) { 92 current_buffer_ = kInvalidCurBuffer; 93 } 94 95 free_buffers_.push_front(&buffers_[buffer_index]); 96 return ZX_OK; 97} 98 99uint64_t VmoPool::CurrentBufferSize() const { 100 if (HasBufferInProgress()) { 101 return buffers_[current_buffer_].buffer.size(); 102 } 103 return 0; 104} 105void* VmoPool::CurrentBufferAddress() const { 106 if (HasBufferInProgress()) { 107 return buffers_[current_buffer_].buffer.start(); 108 } 109 return nullptr; 110} 111} // namespace fzl 112