From 70f97b8291454efbf9606051352c15ea6ebca319 Mon Sep 17 00:00:00 2001 From: Richard Thier Date: Sun, 29 Sep 2024 18:00:32 +0200 Subject: [PATCH] Initial version --- arena.h | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 arena.h diff --git a/arena.h b/arena.h new file mode 100644 index 0000000..f71396a --- /dev/null +++ b/arena.h @@ -0,0 +1,103 @@ +// Gradual-commit arena demonstration +// This is free and unencumbered software released into the public domain. +/* Usage: + * + * arena a = newarena((ptrdiff_t)1 << 33); + * if (!alloc(a, size, align, count)) { + * break; + * } + * total += size * count; + */ +#ifndef ARENA_H +#define ARENA_H + +#include +#include + +static void *os_reserve(ptrdiff_t); +static char os_commit(void *, ptrdiff_t); + +#define ARENA_PAGESIZE ((ptrdiff_t)1<<26) + +typedef struct { + char *begin; + char *commit; + char *end; +} arena; + +static arena newarena(ptrdiff_t cap) +{ + arena a = {0}; + cap += -cap & (ARENA_PAGESIZE - 1); + a.begin = a.commit = a.end = (char*) os_reserve(cap); + if (a.begin) { + a.end += cap; + } + return a; +} + +static void *alloc(arena *a, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count) +{ + ptrdiff_t padding = -(size_t)a->begin & (align - 1); + ptrdiff_t committed = a->commit - a->begin; + if (count > (committed-padding)/size) { + ptrdiff_t reserved = a->end - a->begin; + if (count > (reserved-padding)/size) { + return 0; + } + + ptrdiff_t needed = size*count + padding - committed; + needed += -needed & (ARENA_PAGESIZE - 1); + if (!os_commit(a->commit, needed)) { + return 0; + } + a->commit += needed; + } + + void *ptr = a->begin + padding; + a->begin += padding + size*count; + + // Change to this instead if you want zero-inited (but this gets slow with many arenas) + //return memset(ptr, 0, size*count); + return ptr; +} + +#ifdef _WIN32 +// $ cc -g3 -nostartfiles -o arena.exe arena.c +// $ cl /Z7 arena.c /link /subsystem:console kernel32.lib libvcruntime.lib +#define W32(r) __declspec(dllimport) r __stdcall +W32(void) ExitProcess(int); +W32(void *) VirtualAlloc(void *, ptrdiff_t, int, int); + +#define MEM_COMMIT 0x1000 +#define MEM_RESERVE 0x2000 +#define PAGE_NOACCESS 0x0001 +#define PAGE_READWRITE 0x0004 + +static void *os_reserve(ptrdiff_t cap) +{ + return VirtualAlloc(0, cap, MEM_RESERVE, PAGE_NOACCESS); +} + +static char os_commit(void *ptr, ptrdiff_t len) +{ + return VirtualAlloc(ptr, len, MEM_COMMIT, PAGE_READWRITE); +} + +#else // POSIX +// $ cc -g3 -o arena arena.c +#include + +static void *os_reserve(ptrdiff_t cap) +{ + void *r = mmap(0, cap, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + return r==MAP_FAILED ? 0 : r; +} + +static char os_commit(void *ptr, ptrdiff_t len) +{ + return !mprotect(ptr, len, PROT_READ|PROT_WRITE); +} +#endif // POSIX + +#endif /* ARENA_H */