summaryrefslogtreecommitdiff
path: root/src/memory/arena.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-02-21 13:16:58 +1100
committerjacqueline <me@jacqueline.id.au>2023-02-21 13:19:11 +1100
commit941bafca17b13547a88668b787ce4c8e064ef7ff (patch)
treeb4a0d5528cbd258fedffc041dee837bcaf1f690f /src/memory/arena.cpp
parent12d2ffdab70df573610b81d8a24545da33bb67e3 (diff)
downloadtangara-fw-941bafca17b13547a88668b787ce4c8e064ef7ff.tar.gz
Add a memory arena for the audio pipeline
Diffstat (limited to 'src/memory/arena.cpp')
-rw-r--r--src/memory/arena.cpp75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/memory/arena.cpp b/src/memory/arena.cpp
new file mode 100644
index 00000000..450ac4f2
--- /dev/null
+++ b/src/memory/arena.cpp
@@ -0,0 +1,75 @@
+#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() {
+ // TODO: assert queue is full?
+ 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 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