/* * Copyright 2023 jacqueline * * SPDX-License-Identifier: GPL-3.0-only */ #include "arena.hpp" #include #include #include "esp_heap_caps.h" #include "freertos/queue.h" #include "span.hpp" namespace memory { Arena::Arena(std::size_t block_size, std::size_t num_blocks, uint32_t alloc_flags) : block_size_(block_size) { pool_ = static_cast( heap_caps_malloc(block_size * num_blocks, alloc_flags)); free_blocks_ = xQueueCreate(num_blocks, sizeof(void*)); for (int i = 0; i < num_blocks; i++) { std::byte* block = pool_ + (i * block_size); xQueueSend(free_blocks_, &block, 0); } } Arena::~Arena() { // We shouldn't have any blocks in use when destroying an arena. assert(uxQueueSpacesAvailable(free_blocks_) == 0); vQueueDelete(free_blocks_); free(pool_); } auto Arena::Acquire() -> std::optional { std::byte* block; bool result = xQueueReceive(free_blocks_, &block, 0); if (result) { ArenaPtr ptr{this, block, block_size_, 0}; return ptr; } else { return {}; } } auto Arena::Return(ArenaPtr ptr) -> void { assert(ptr.owner == this); xQueueSend(free_blocks_, &ptr.start, 0); } auto Arena::BlocksFree() -> std::size_t { return uxQueueMessagesWaiting(free_blocks_); } auto ArenaRef::Acquire(Arena* a) -> std::optional { auto ptr = a->Acquire(); if (ptr) { ArenaRef ref{*ptr}; return ref; } return {}; } ArenaRef::ArenaRef(ArenaPtr p) : ptr(p) {} ArenaRef::ArenaRef(ArenaRef&& other) : ptr(other.Release()) {} auto ArenaRef::Release() -> ArenaPtr { auto ret = ptr; ptr.owner = nullptr; ptr.start = nullptr; ptr.size = 0; ptr.used_size = 0; return ret; } ArenaRef::~ArenaRef() { if (ptr.owner != nullptr) { ptr.owner->Return(ptr); } } } // namespace memory