You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
1.8 KiB
86 lines
1.8 KiB
/*
|
|
* Copyright 2023 jacqueline <me@jacqueline.id.au>
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-only
|
|
*/
|
|
|
|
#include "arena.hpp"
|
|
|
|
#include <cstdint>
|
|
#include <optional>
|
|
|
|
#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<std::byte*>(
|
|
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<ArenaPtr> {
|
|
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<ArenaRef> {
|
|
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
|
|
|