// 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 */