summaryrefslogtreecommitdiff
path: root/src/smrt_arena.c
diff options
context:
space:
mode:
authorsteven-na <noreply.github@stvnc.dev>2026-07-28 02:12:54 -0700
committersteven-na <noreply.github@stvnc.dev>2026-07-28 02:12:54 -0700
commit8bec6205ae1631dc0896fe25795b2946ed414df0 (patch)
treea40734bf042ab2236c65254bed08fac23bccc3e5 /src/smrt_arena.c
parentacea02e9b90a83167d15e62741c8e8bb9f0d4b7c (diff)
Arenas and start work on strings
Diffstat (limited to 'src/smrt_arena.c')
-rw-r--r--src/smrt_arena.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/smrt_arena.c b/src/smrt_arena.c
new file mode 100644
index 0000000..683afcd
--- /dev/null
+++ b/src/smrt_arena.c
@@ -0,0 +1,197 @@
+#if defined(__linux__)
+#define _DEFAULT_SOURCE
+#endif
+
+#include "common.h"
+#include "smrt_arena.h"
+
+#include <string.h>
+
+smrt_arena_t *smrt_arena_create(u64 reserve_size, u64 commit_size, b32 auto_decommit) {
+ u32 pagesize = plat_get_pagesize();
+
+ reserve_size = ALIGN_UP_POW2(reserve_size + sizeof(smrt_arena_t), pagesize);
+ commit_size = ALIGN_UP_POW2( commit_size, pagesize);
+
+ smrt_arena_t *arena = plat_mem_reserve(reserve_size);
+
+ if (!plat_mem_commit(arena, commit_size)) {
+ return NULL;
+ }
+
+ arena->reserve_size = reserve_size;
+ arena->commit_size = commit_size;
+ arena->commit_pos = commit_size;
+ arena->pos = SMRT_ARENA_BASE_POS;
+ arena->mark_pos = 0;
+ arena->auto_decommit = auto_decommit;
+
+ return arena;
+
+}
+
+static void smrt_arena__shrink_commit(smrt_arena_t *arena) {
+ if (!arena->auto_decommit) { return; }
+
+ u64 target_commit_pos = arena->pos + arena->commit_size - 1;
+ target_commit_pos -= target_commit_pos % arena->commit_size;
+
+ if (target_commit_pos >= arena->commit_pos) { return; }
+
+ u64 decommit_size = arena->commit_pos - target_commit_pos;
+ u8 *decommit_start = (u8*)arena + target_commit_pos;
+
+ if (plat_mem_decommit(decommit_start, decommit_size)) {
+ arena->commit_pos = target_commit_pos;
+
+ if (arena->mark_pos > arena->commit_pos) {
+ arena->mark_pos = 0;
+ }
+ }
+}
+
+void *smrt_arena_push(smrt_arena_t *arena, u64 alloc_amount, b32 zero_out) {
+ u64 pos_aligned = ALIGN_UP_POW2(arena->pos, ARENA_ALIGN);
+ u64 new_pos = pos_aligned + alloc_amount;
+
+ if (new_pos > arena->reserve_size) { return NULL; }
+
+ if (new_pos > arena->commit_pos) {
+ u64 new_commit_pos = new_pos;
+ new_commit_pos += arena->commit_size - 1;
+ new_commit_pos -= new_commit_pos % arena->commit_size;
+ new_commit_pos = MIN(new_commit_pos, arena->reserve_size);
+
+ u8 *mem = (u8*)arena + arena->commit_pos;
+ u64 commit_size = new_commit_pos - arena->commit_pos;
+
+ if (!plat_mem_commit(mem, commit_size)) {
+ return NULL;
+ }
+
+ arena->commit_pos = new_commit_pos;
+ }
+
+ arena->pos = new_pos;
+
+ u8 *out = (u8*)arena + pos_aligned;
+
+ if (zero_out) {
+ memset(out, 0, alloc_amount);
+ }
+
+ return out;
+}
+
+void *smrt_arena_mark_push(smrt_arena_t *arena, u64 alloc_amount, b32 zero_out) {
+ u64 orig_pos = arena->pos;
+
+ void *mem = smrt_arena_push(arena, alloc_amount, zero_out);
+
+ if (mem) {
+ arena->mark_pos = orig_pos;
+ }
+
+ return mem;
+}
+
+void smrt_arena_pop(smrt_arena_t *arena, u64 pop_amount) {
+ pop_amount = MIN(pop_amount, arena->pos - SMRT_ARENA_BASE_POS);
+ arena->pos -= pop_amount;
+
+ smrt_arena__shrink_commit(arena);
+}
+
+void smrt_arena_pop_to(smrt_arena_t *arena, u64 pos) {
+ u64 size = pos < arena->pos ? arena->pos - pos : 0;
+ smrt_arena_pop(arena, size);
+}
+
+b32 smrt_arena_pop_to_mark(smrt_arena_t *arena) {
+ if (arena->mark_pos == 0) {
+ return false;
+ }
+
+ smrt_arena_pop_to(arena, arena->mark_pos);
+
+ return true;
+}
+
+void smrt_arena_clear(smrt_arena_t *arena, b32 zero_out) {
+ arena->pos = SMRT_ARENA_BASE_POS;
+
+ if (zero_out) {
+ memset((u8*)arena + SMRT_ARENA_BASE_POS, 0, arena->commit_size - SMRT_ARENA_BASE_POS);
+ }
+
+ smrt_arena__shrink_commit(arena);
+}
+
+void smrt_arena_destroy(smrt_arena_t *arena) {
+ plat_mem_release(arena, arena->reserve_size);
+}
+
+#if defined(_WIN32)
+
+#include <windows.h>
+
+u32 plat_get_pagesize(void) {
+ SYSTEM_INFO sysinfo = { 0 };
+ GetSystemInfo(&sysinfo);
+
+ return sysinfo.dwPageSize;
+}
+
+void* plat_mem_reserve(u64 size) {
+ return VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_READWRITE);
+}
+
+b32 plat_mem_commit(void* ptr, u64 size) {
+ void* ret = VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE);
+ return ret != NULL;
+}
+
+b32 plat_mem_decommit(void* ptr, u64 size) {
+ return VirtualFree(ptr, size, MEM_DECOMMIT);
+}
+
+b32 plat_mem_release(void* ptr, u64 size) {
+ return VirtualFree(ptr, size, MEM_RELEASE);
+}
+
+
+#elif defined(__linux__)
+
+#include <unistd.h>
+#include <sys/mman.h>
+
+u32 plat_get_pagesize(void) {
+ return (u32)sysconf(_SC_PAGESIZE);
+}
+
+void* plat_mem_reserve(u64 size) {
+ void* out = mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (out == MAP_FAILED) {
+ return NULL;
+ }
+ return out;
+}
+
+b32 plat_mem_commit(void* ptr, u64 size) {
+ i32 ret = mprotect(ptr, size, PROT_READ | PROT_WRITE);
+ return ret == 0;
+}
+
+b32 plat_mem_decommit(void* ptr, u64 size) {
+ i32 ret = mprotect(ptr, size, PROT_NONE);
+ if (ret != 0) return false;
+ ret = madvise(ptr, size, MADV_DONTNEED);
+ return ret == 0;
+}
+
+b32 plat_mem_release(void* ptr, u64 size) {
+ i32 ret = munmap(ptr, size);
+ return ret == 0;
+}
+
+#endif