Skip to content

Instantly share code, notes, and snippets.

@Magicalbat
Last active December 30, 2025 02:39
Show Gist options
  • Select an option

  • Save Magicalbat/4e085cadeed46c7b6f917ea9e9220d6a to your computer and use it in GitHub Desktop.

Select an option

Save Magicalbat/4e085cadeed46c7b6f917ea9e9220d6a to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef i8 b8;
typedef i32 b32;
#define KiB(n) ((u64)(n) << 10)
#define MiB(n) ((u64)(n) << 20)
#define GiB(n) ((u64)(n) << 30)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define ALIGN_UP_POW2(n, p) (((u64)(n) + ((u64)(p) - 1)) & (~((u64)(p) - 1)))
#define ARENA_BASE_POS (sizeof(mem_arena))
#define ARENA_ALIGN (sizeof(void*))
typedef struct {
u64 reserve_size;
u64 commit_size;
u64 pos;
u64 commit_pos;
} mem_arena;
mem_arena* arena_create(u64 reserve_size, u64 commit_size);
void arena_destroy(mem_arena* arena);
void* arena_push(mem_arena* arena, u64 size, b32 non_zero);
void arena_pop(mem_arena* arena, u64 size);
void arena_pop_to(mem_arena* arena, u64 pos);
void arena_clear(mem_arena* arena);
#define PUSH_STRUCT(arena, T) (T*)arena_push((arena), sizeof(T), false)
#define PUSH_STRUCT_NZ(arena, T) (T*)arena_push((arena), sizeof(T), true)
#define PUSH_ARRAY(arena, T, n) (T*)arena_push((arena), sizeof(T) * (n), false)
#define PUSH_ARRAY_NZ(arena, T, n) (T*)arena_push((arena), sizeof(T) * (n), true)
u32 plat_get_pagesize(void);
void* plat_mem_reserve(u64 size);
b32 plat_mem_commit(void* ptr, u64 size);
b32 plat_mem_decommit(void* ptr, u64 size);
b32 plat_mem_release(void* ptr, u64 size);
int main(void) {
mem_arena* perm_arena = arena_create(GiB(1), MiB(1));
while (1) {
arena_push(perm_arena, MiB(16), false);
getc(stdin);
}
arena_destroy(perm_arena);
return 0;
}
mem_arena* arena_create(u64 reserve_size, u64 commit_size) {
u32 pagesize = plat_get_pagesize();
reserve_size = ALIGN_UP_POW2(reserve_size, pagesize);
commit_size = ALIGN_UP_POW2(commit_size, pagesize);
mem_arena* 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->pos = ARENA_BASE_POS;
arena->commit_pos = commit_size;
return arena;
}
void arena_destroy(mem_arena* arena) {
plat_mem_release(arena, arena->reserve_size);
}
void* arena_push(mem_arena* arena, u64 size, b32 non_zero) {
u64 pos_aligned = ALIGN_UP_POW2(arena->pos, ARENA_ALIGN);
u64 new_pos = pos_aligned + size;
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 (!non_zero) {
memset(out, 0, size);
}
return out;
}
void arena_pop(mem_arena* arena, u64 size) {
size = MIN(size, arena->pos - ARENA_BASE_POS);
arena->pos -= size;
}
void arena_pop_to(mem_arena* arena, u64 pos) {
u64 size = pos < arena->pos ? arena->pos - pos : 0;
arena_pop(arena, size);
}
void arena_clear(mem_arena* arena) {
arena_pop_to(arena, ARENA_BASE_POS);
}
#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__)
#define _DEFAULT_SOURCE
#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
@Juskr04
Copy link

Juskr04 commented Dec 23, 2025

u64 new_commit_pos = new_pos;
new_commit_pos += arena->commit_size - 1;
new_commit_pos -= new_commit_pos % arena->commit_size;

Instead of this, can't we just do this :
u64 new_commit_pos = ALIGN_UP_POW2(new_pos, arena->commit_size);

@Magicalbat
Copy link
Author

u64 new_commit_pos = new_pos;
new_commit_pos += arena->commit_size - 1;
new_commit_pos -= new_commit_pos % arena->commit_size;

Instead of this, can't we just do this : u64 new_commit_pos = ALIGN_UP_POW2(new_pos, arena->commit_size);

With this implementation, you cannot actually guarantee that arena->commit_size is a power of two. Obviously, in most cases it probably should be, but aligning it up to a page boundary does not ensure it is a power of two. The code above is a more general way to align up the new_commit_pos

@CarlAugust
Copy link

On line 176 the function plat_get_size has the wrong name making it fail on linux. It should be plat_get_pagesize like in the windows implementation.

@Magicalbat
Copy link
Author

On line 176 the function plat_get_size has the wrong name making it fail on linux. It should be plat_get_pagesize like in the windows implementation.

Just fixed it, sorry for the mistake

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment