fix up free list allocator, add realloc
This commit is contained in:
parent
f0147195b6
commit
c7db4177fa
166
src/allocators.c
166
src/allocators.c
@ -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;
|
||||
next = current->next;
|
||||
pMemFree(current, current->size);
|
||||
current = next;
|
||||
}
|
||||
|
||||
alloc->list_count = 1;
|
||||
}
|
||||
current = alloc->list_head;
|
||||
|
||||
FLNode *node = (FLNode *)alloc->lists[0]->data;
|
||||
node->size = alloc->lists[0]->size;
|
||||
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);
|
||||
|
||||
@ -79,14 +79,13 @@ typedef struct FreeList
|
||||
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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user