Created
September 1, 2024 04:10
-
-
Save stillwwater/5c341c7859c52a49a20fba8db8b1a7d1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct arena { | |
usize commitsize; | |
char *name; | |
char *start; // start of reserved address space | |
char *end; // end of reserved address space | |
char *heap; // start of user block | |
char *allocated; // end of allocated block | |
char *commited; // end of commited block | |
}; | |
// Allocates a memory arena. Capacity should be at least the allocation | |
// granularity on the system (64KB on Windows). | |
// | |
// capacity: | |
// Amount of the address space to be reserved for this arena. | |
struct arena * | |
make_arena(char *name, usize capacity) | |
{ | |
struct arena *arena; | |
// we could deal with this edge case if we wanted | |
assert(sysinfo.dwPageSize >= sizeof(*arena)); | |
assert(capacity >= sizeof(*arena)); | |
assert(capacity >= sysinfo.dwAllocationGranularity); | |
// reserve address space | |
arena = VirtualAlloc(NULL, capacity, MEM_RESERVE, PAGE_NOACCESS); | |
if (!arena) | |
fatal_error("MEM_RESERVE failed for '%s' (0x%lX)", name, GetLastError()); | |
// commit 1 page of memory to use for the arena header | |
arena = VirtualAlloc(arena, sysinfo.dwPageSize, MEM_COMMIT, PAGE_READWRITE); | |
if (!arena) | |
fatal_error("MEM_COMMIT failed for '%s' (0x%lX)", name, GetLastError()); | |
arena->name = name; | |
arena->start = (char *)arena; | |
arena->end = arena->start + capacity; | |
arena->heap = arena->start + sysinfo.dwPageSize; | |
arena->allocated = arena->heap; | |
arena->commited = arena->heap; | |
if (capacity < ARENA_2MB) | |
arena->commitsize = ARENA_COMMIT_SMALL; | |
else if (capacity < ARENA_200MB) | |
arena->commitsize = ARENA_COMMIT_LARGE; | |
else | |
arena->commitsize = ARENA_COMMIT_GIGANTIC; | |
return arena; | |
} | |
// Deallocates memory reserved for an arena. | |
void | |
free_arena(struct arena *arena) | |
{ | |
BOOL result = VirtualFree(arena->start, 0, MEM_RELEASE); | |
assert(result); | |
} | |
// Resets the arena, essentially freeing all allocated objects. Does not | |
// decommit the underlying memory used by the arena, use free_arena to actually | |
// free the memory. | |
void | |
arena_clear(struct arena *arena) | |
{ | |
// should memory be decommited? | |
arena->allocated = arena->heap; | |
} | |
__attribute((noinline)) void * | |
arena_resize(struct arena *arena, void *ptr, usize count) | |
{ | |
usize commit; | |
// round to next commit size | |
commit = arena->commitsize + (count & ~(arena->commitsize - 1)); | |
if (arena->commited + commit > arena->end) | |
return NULL; | |
if (!VirtualAlloc(arena->commited, commit, MEM_COMMIT, PAGE_READWRITE)) | |
return NULL; | |
arena->commited += commit; | |
#ifndef NDEBUG | |
memset(ptr, 0xCC, count); | |
#endif | |
return ptr; | |
} | |
// Allocates an object on the arena. Returns NULL if the arena is full. | |
// | |
// align: | |
// Alignment in bytes of the memory returned. Must be a power of two size. | |
void * | |
arena_alloc_align(struct arena *arena, usize align, usize count) | |
{ | |
void *ptr; | |
assert(!(align & (align - 1))); | |
// align the end of allocated block | |
arena->allocated += (align - ((usize)arena->allocated & (align - 1))); | |
ptr = arena->allocated; | |
arena->allocated += count; | |
if (__builtin_expect(arena->allocated > arena->commited, 0)) { | |
return arena_resize(arena, ptr, count); | |
} | |
#ifndef NDEBUG | |
memset(ptr, 0xCC, count); | |
#endif | |
return ptr; | |
} | |
// Allocates an object on the arena. The result returned is 16-byte aligned. | |
// Returns NULL if the arena is full. | |
void * | |
arena_alloc(struct arena *arena, usize count) | |
{ | |
return arena_alloc_align(arena, 16, count); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment