diff options
| author | steven-na <noreply.github@stvnc.dev> | 2026-07-28 02:12:54 -0700 |
|---|---|---|
| committer | steven-na <noreply.github@stvnc.dev> | 2026-07-28 02:12:54 -0700 |
| commit | 8bec6205ae1631dc0896fe25795b2946ed414df0 (patch) | |
| tree | a40734bf042ab2236c65254bed08fac23bccc3e5 /src/smrt_arena.c | |
| parent | acea02e9b90a83167d15e62741c8e8bb9f0d4b7c (diff) | |
Arenas and start work on strings
Diffstat (limited to 'src/smrt_arena.c')
| -rw-r--r-- | src/smrt_arena.c | 197 |
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 |