Skip to content

Instantly share code, notes, and snippets.

@skeeto
Created May 25, 2024 00:43
Show Gist options
  • Save skeeto/dac3317691836ad0836dad0655831163 to your computer and use it in GitHub Desktop.
Save skeeto/dac3317691836ad0836dad0655831163 to your computer and use it in GitHub Desktop.
Growing arena persisting commit level through scratch copies
#define assert(c) while (!(c)) __builtin_unreachable()
#define new(a, n, t) (t *)alloc(a, n, sizeof(t), _Alignof(t))
enum { PAGESIZE = 1<<12 };
typedef signed int b32;
typedef signed int i32;
typedef char byte;
typedef signed long long iz;
typedef unsigned long long uz;
static byte *os_reserve(iz);
static b32 os_commit(byte *, iz);
typedef struct {
byte *beg;
byte *end;
byte **commit;
} arena;
static arena newarena(iz cap)
{
arena r = {0};
r.end = r.beg = os_reserve(cap);
if (r.beg) {
if (!os_commit(r.beg, PAGESIZE)) {
return r;
}
r.end += cap;
r.commit = (byte **)r.beg;
*r.commit = r.beg + PAGESIZE;
r.beg += sizeof(void *);
}
return r;
}
static byte *alloc(arena *a, iz count, iz size, iz align)
{
assert(align <= PAGESIZE); // simplifying assumption
iz pad = -(uz)a->beg & (align - 1);
assert(count < (a->end - a->beg - pad)/size); // OOM: too large
a->beg += pad; // align for remainder
iz total = count * size;
iz shortfall = total - (*a->commit - a->beg);
if (shortfall > 0) {
iz npages = (shortfall + PAGESIZE - 1) / PAGESIZE;
b32 ok = os_commit(*a->commit, npages*PAGESIZE);
assert(ok); // OOM: commit failed
*a->commit += npages * PAGESIZE;
}
byte *r = a->beg;
a->beg += total;
return __builtin_memset(r, 0, total);
}
static i32 run(void)
{
arena perm = newarena((iz)1<<40);
for (iz n = 0; n < 1<<10; n++) {
// Commits should only happen on first iteration despite a
// per-iteration scratch arena. That is, the commit level
// persists between copies of the arena struct. I placed a
// couple of GDB dprintf probes to test this.
arena scratch = perm;
for (iz i = 0; i < (iz)1<<16; i++) {
new(&scratch, 1<<4, int);
}
}
return 0;
}
#define W32(r) __declspec(dllimport) r __stdcall
W32(void) ExitProcess(i32);
W32(byte *) VirtualAlloc(byte *, iz, i32, i32);
static byte *os_reserve(iz cap)
{
enum { MEM_RESERVE = 0x2000, PAGE_NOACCESS = 1 };
return VirtualAlloc(0, cap, MEM_RESERVE, PAGE_NOACCESS);
}
static b32 os_commit(byte *p, iz len)
{
enum { MEM_COMMIT = 0x1000, PAGE_READWRITE = 4 };
return !!VirtualAlloc(p, len, MEM_COMMIT, PAGE_READWRITE);
}
void mainCRTStartup(void)
{
i32 r = run();
ExitProcess(r);
assert(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment