aboutsummaryrefslogtreecommitdiff
path: root/sys/libn
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2020-04-21 13:29:38 -0700
committerNicholas Noll <nbnoll@eml.cc>2020-04-21 13:29:38 -0700
commit7d254c81400128923d1952909bf22b1784e540fc (patch)
tree671ecbf2e1d18f97b29c81a6666d8fb9d6979d3c /sys/libn
parentaa064359cb514251a73b53de3e530fa89f687ab7 (diff)
feat: added simple memory arena allocator to libn
Diffstat (limited to 'sys/libn')
-rw-r--r--sys/libn/memory.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/sys/libn/memory.c b/sys/libn/memory.c
index d3deef7..6b715d9 100644
--- a/sys/libn/memory.c
+++ b/sys/libn/memory.c
@@ -48,3 +48,92 @@ _bufpop(void *buf, int i, vlong eltsize)
_bufHdr(buf)->len--;
}
+// -------------------------------------------------------------------------
+// Arena allocator
+
+#define ARENA_ALIGN 8
+#define ARENA_BLOCK_SIZE 1024 * 1024
+
+#define ALIGN_DOWN(n, a) ((n) & ~((a)-1))
+#define ALIGN_UP(n, a) ALIGN_DOWN((n) + (a)-1, (a))
+#define ALIGN_DOWN_PTR(p, a) ((void*)ALIGN_DOWN((uintptr)(p), (a)))
+#define ALIGN_UP_PTR(p, a) ((void*)ALIGN_UP((uintptr)(p), (a)))
+
+struct Block
+{
+ struct Block *next;
+ byte buf[];
+};
+
+struct mem·Arena
+{
+ mem·Allocator heap;
+ byte *off;
+ byte *end;
+ struct Block *curr;
+ struct Block first;
+};
+
+mem·Arena*
+mem·newarena(mem·Allocator from)
+{
+ mem·Arena *a = from.alloc(sizeof(*a) + ARENA_BLOCK_SIZE);
+ a->heap = from;
+ a->off = a->first.buf;
+ a->end = a->first.buf + ARENA_BLOCK_SIZE;
+ a->curr = &a->first;
+ a->first.next = nil;
+
+ return a;
+}
+
+void
+grow(mem·Arena *a, vlong min)
+{
+ uintptr size;
+ struct Block *blk;
+
+ size = ALIGN_UP(MAX(min, ARENA_BLOCK_SIZE), ARENA_ALIGN);
+ blk = a->heap.alloc(sizeof(*blk) + size);
+ a->off = blk->buf;
+ a->end = a->off + size;
+
+ Assert(a->curr->next == nil);
+ Assert(a->off == ALIGN_DOWN_PTR(a->off, ARENA_ALIGN));
+
+ a->curr->next = blk;
+ a->curr = blk;
+}
+
+void*
+mem·arenaalloc(mem·Arena *a, ulong size)
+{
+ void *ptr;
+ if (size > (ulong)(a->end - a->off)) {
+ grow(a, size);
+ Assert(size <= (uintptr)(a->end - a->off));
+ }
+
+ ptr = a->off;
+ a->off = ALIGN_UP_PTR(a->off + size, ARENA_ALIGN);
+
+ Assert(a->off <= a->end);
+ Assert(ptr == ALIGN_DOWN_PTR(ptr, ARENA_ALIGN));
+
+ return ptr;
+}
+
+void
+mem·freearena(mem·Arena *a)
+{
+ struct Block *it, *next;
+
+ it = &a->first;
+ while (it != nil) {
+ next = it->next;
+ a->heap.free(it);
+ it = next;
+ }
+
+ a->heap.free(a);
+}