fix up free list allocator, add realloc

This commit is contained in:
Matthew 2025-05-19 19:44:08 +10:00
parent f0147195b6
commit c7db4177fa
2 changed files with 128 additions and 65 deletions

View File

@ -3,6 +3,7 @@
FLAlloc FL_ALLOC = {0};
Allocator ALLOC = {0};
read_only FLNode FL_NIL_NODE = {0};
read_only FreeList FL_NIL_LIST = {0};
constexpr usize FL_GLOBAL_SIZE = MB(32);
static b32 FL_GLOBAL_INIT = false;
@ -209,30 +210,73 @@ static void GlobalFreeListInit(usize size)
static rawptr FLMemAlloc(usize size)
{
if (!FL_GLOBAL_INIT)
{
GlobalFreeListInit(FL_GLOBAL_SIZE);
}
return FreeListAlloc(&FL_ALLOC, size);
}
static rawptr FLMemAllocZeroed(usize size)
{
rawptr ptr = FreeListAlloc(&FL_ALLOC, size);
rawptr ptr = FLMemAlloc(size);
MemZero(ptr, size);
return ptr;
}
static rawptr FLMemRealloc(rawptr old_ptr, usize size)
{
return FreeListRealloc(&FL_ALLOC, old_ptr, size);
}
static void FLMemFree(rawptr ptr)
{
FreeListFree(&FL_ALLOC, ptr);
}
/*
* Should be async safe given no other thread frees a pointer in the middle of a realloc
*/
static rawptr FreeListRealloc(FLAlloc *alloc, rawptr old_ptr, usize size)
{
rawptr ptr = FreeListAlloc(alloc, size);
usize old_size = FreeListPtrSize(alloc, old_ptr);
MemCpy(ptr, old_ptr, old_size);
FreeListFree(alloc, old_ptr);
return ptr;
}
static usize FreeListPtrSize(FLAlloc *alloc, rawptr ptr)
{
if (ptr == NULL) return 0;
usize size = 0;
TicketMutLock(&alloc->mut);
FreeList *list = _FreeListFindList(alloc, ptr);
if (list != NULL)
{
FLAllocHeader *header = cast(FLAllocHeader *, u8ptr(ptr) - sizeof(FLAllocHeader));
size = header->size + header->padding;
}
TicketMutUnlock(&alloc->mut);
return size;
}
static void FreeListInit(FLAlloc *alloc, usize size)
{
alloc->lists = pMemAllocZeroed(sizeof(FreeList *) * 16);
alloc->list_count = 1;
alloc->list_capacity = 16;
alloc->list_head = pMemAllocZeroed(sizeof(FreeList));
alloc->nil = &FL_NIL_NODE;
alloc->grow_size = size;
_FreeListInit(&alloc->lists[0], size);
_FreeListInit(&alloc->list_head, size);
FreeListFreeAll(alloc);
}
@ -243,29 +287,30 @@ static void _FreeListInit(FreeList **alloc, usize size)
(*alloc)->data = (rawptr)(((uintptr)*alloc) + ((uintptr)sizeof(FreeList)));
(*alloc)->size = size;
(*alloc)->used = sizeof(FreeList);
(*alloc)->next = &FL_NIL_LIST;
}
static void FreeListFreeAll(FLAlloc *alloc)
{
TicketMutLock(&alloc->mut);
if (alloc->list_count > 1)
FreeList *current = alloc->list_head->next;
FreeList *next = &FL_NIL_LIST;
while (current != &FL_NIL_LIST)
{
for (u32 i = 1; i < alloc->list_count; i++)
{
pMemFree(alloc->lists[i], alloc->lists[i]->size);
alloc->lists[i] = NULL;
}
alloc->list_count = 1;
next = current->next;
pMemFree(current, current->size);
current = next;
}
FLNode *node = (FLNode *)alloc->lists[0]->data;
node->size = alloc->lists[0]->size;
current = alloc->list_head;
FLNode *node = (FLNode *)current->data;
node->size = current->size;
node->next = &FL_NIL_NODE;
alloc->lists[0]->head = node;
alloc->lists[0]->used = sizeof(FreeList);
current->head = node;
current->used = sizeof(FreeList);
TicketMutUnlock(&alloc->mut);
}
@ -300,30 +345,35 @@ static FLNode *FreeListSearch(FreeList *alloc, usize size, usize alignment, usiz
/*
* NOT SAFE TO CALL OUTSIDE OF FreeListAlloc
*/
static void FreeListGrow(FLAlloc *alloc, usize alloc_size)
static FreeList *FreeListGrow(FLAlloc *alloc, usize alloc_size)
{
alloc->list_count += 1;
u32 i = alloc->list_count;
if (i >= alloc->list_capacity)
{
alloc->list_capacity += 16;
rawptr new_mem = pMemAlloc(sizeof(FreeList *) * alloc->list_capacity);
MemCpy(new_mem, alloc->lists, i);
pMemFree(alloc->lists, sizeof(FreeList *) * i);
alloc->lists = new_mem;
}
usize grow_size = alloc->grow_size;
if (alloc_size > grow_size)
grow_size += alloc_size;
_FreeListInit(&alloc->lists[i], grow_size);
FreeList *list = NULL;
FLNode *node = (FLNode *)alloc->lists[i]->data;
node->size = alloc->lists[i]->size;
_FreeListInit(&list, grow_size);
FLNode *node = (FLNode *)list->data;
node->size = list->size;
node->next = alloc->nil;
alloc->lists[i]->head = node;
list->head = node;
FreeList *current = alloc->list_head;
while (current != &FL_NIL_LIST)
{
if (current->next == &FL_NIL_LIST)
{
current->next = list;
break;
}
current = current->next;
}
return list;
}
static rawptr _FreeListAllocAlign(FreeList *alloc, usize size, usize alignment)
@ -375,28 +425,25 @@ static rawptr FreeListAlloc(FLAlloc *alloc, usize size)
static rawptr FreeListAllocAlign(FLAlloc *alloc, usize size, usize alignment)
{
if (!FL_GLOBAL_INIT)
{
GlobalFreeListInit(FL_GLOBAL_SIZE);
}
TicketMutLock(&alloc->mut);
FreeList *fl = NULL;
for (u32 i = 0; i < alloc->list_count; i++)
FreeList *fl = &FL_NIL_LIST;
FreeList *current = alloc->list_head;
while (current != &FL_NIL_LIST)
{
usize remaining = alloc->lists[i]->size - alloc->lists[i]->used;
usize remaining = current->size - current->used;
if (size < remaining)
{
fl = alloc->lists[i];
fl = current;
break;
}
current = current->next;
}
if (fl == NULL)
if (fl == &FL_NIL_LIST)
{
FreeListGrow(alloc, size);
fl = alloc->lists[alloc->list_count-1];
fl = FreeListGrow(alloc, size);
}
rawptr ptr = _FreeListAllocAlign(fl, size, alignment);
@ -406,6 +453,25 @@ static rawptr FreeListAllocAlign(FLAlloc *alloc, usize size, usize alignment)
return ptr;
}
static FreeList *_FreeListFindList(FLAlloc *alloc, rawptr ptr)
{
FreeList *list = NULL;
FreeList *current = alloc->list_head;
while (current != &FL_NIL_LIST)
{
uintptr ptr_addr = uintptr(ptr);
uintptr start = uintptr(current->data);
uintptr end = uintptr(current->data) + uintptr(current->size);
if (ptr_addr >= start && ptr_addr < end)
{
list = current;
break;
}
}
return list;
}
static void _FreeListFree(FreeList *alloc, rawptr ptr)
{
FLAllocHeader *header = cast(FLAllocHeader *, u8ptr(ptr) - sizeof(FLAllocHeader));
@ -438,16 +504,10 @@ static void FreeListFree(FLAlloc *alloc, rawptr ptr)
TicketMutLock(&alloc->mut);
for (u32 i = 0; i < alloc->list_count; i++)
FreeList *list = _FreeListFindList(alloc, ptr);
if (list != NULL)
{
uintptr ptr_addr = uintptr(ptr);
uintptr start = uintptr(alloc->lists[i]->data);
uintptr end = uintptr(alloc->lists[i]->data) + uintptr(alloc->lists[i]->size);
if (ptr_addr >= start && ptr_addr < end)
{
_FreeListFree(alloc->lists[i], ptr);
break;
}
_FreeListFree(list, ptr);
}
TicketMutUnlock(&alloc->mut);

View File

@ -75,18 +75,17 @@ typedef struct FLNode
typedef struct FreeList
{
rawptr data;
FLNode *head;
usize size;
usize used;
rawptr data;
FLNode *head;
usize size;
usize used;
struct FreeList *next;
} FreeList;
typedef struct FLAlloc
{
FreeList **lists;
FreeList *list_head;
TicketMut mut;
u32 list_count;
u32 list_capacity;
FLNode *nil;
usize grow_size;
} FLAlloc;
@ -94,18 +93,22 @@ typedef struct FLAlloc
static void GlobalFreeListInit(usize size);
static rawptr FLMemAlloc(usize size);
static rawptr FLMemAllocZeroed(usize size);
static rawptr FLMemRealloc(rawptr old_ptr, usize size);
static void FLMemFree(rawptr ptr);
static void _FreeListInit(FreeList **alloc, usize size);
static usize FreeListPtrSize(FLAlloc *alloc, rawptr ptr);
static void FreeListInit(FLAlloc *alloc, usize size);
static rawptr _FreeListAllocAlign(FreeList *alloc, usize size, usize alignment);
static rawptr FreeListAllocAlign(FLAlloc *alloc, usize size, usize alignment);
static rawptr FreeListAlloc(FLAlloc *alloc, usize size);
static void _FreeListFree(FreeList *alloc, rawptr ptr);
static void FreeListFree(FLAlloc *alloc, rawptr ptr);
static void FreeListFreeAll(FLAlloc *alloc);
static void FreeListGrow(FLAlloc *alloc, usize alloc_size);
static FreeList *FreeListGrow(FLAlloc *alloc, usize alloc_size);
static rawptr FreeListRealloc(FLAlloc *alloc, rawptr old_ptr, usize size);
static FLNode *FreeListSearch(FreeList *alloc, usize size, usize alignment, usize *out_padding, FLNode **prev_node);
static void FreeListCoalescence(FreeList *alloc, FLNode *prev_node, FLNode *free_node);
static void FreeListRemove(FLNode **head, FLNode *prev_node, FLNode *del_node);
static void FreeListInsert(FLNode **head, FLNode *prev_node, FLNode *new_node);
static FreeList *_FreeListFindList(FLAlloc *alloc, rawptr ptr);
static void _FreeListInit(FreeList **alloc, usize size);
static rawptr _FreeListAllocAlign(FreeList *alloc, usize size, usize alignment);
static void _FreeListFree(FreeList *alloc, rawptr ptr);