fix up free list allocator, add realloc
This commit is contained in:
parent
f0147195b6
commit
c7db4177fa
168
src/allocators.c
168
src/allocators.c
@ -3,6 +3,7 @@
|
|||||||
FLAlloc FL_ALLOC = {0};
|
FLAlloc FL_ALLOC = {0};
|
||||||
Allocator ALLOC = {0};
|
Allocator ALLOC = {0};
|
||||||
read_only FLNode FL_NIL_NODE = {0};
|
read_only FLNode FL_NIL_NODE = {0};
|
||||||
|
read_only FreeList FL_NIL_LIST = {0};
|
||||||
|
|
||||||
constexpr usize FL_GLOBAL_SIZE = MB(32);
|
constexpr usize FL_GLOBAL_SIZE = MB(32);
|
||||||
static b32 FL_GLOBAL_INIT = false;
|
static b32 FL_GLOBAL_INIT = false;
|
||||||
@ -209,30 +210,73 @@ static void GlobalFreeListInit(usize size)
|
|||||||
|
|
||||||
static rawptr FLMemAlloc(usize size)
|
static rawptr FLMemAlloc(usize size)
|
||||||
{
|
{
|
||||||
|
if (!FL_GLOBAL_INIT)
|
||||||
|
{
|
||||||
|
GlobalFreeListInit(FL_GLOBAL_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
return FreeListAlloc(&FL_ALLOC, size);
|
return FreeListAlloc(&FL_ALLOC, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static rawptr FLMemAllocZeroed(usize size)
|
static rawptr FLMemAllocZeroed(usize size)
|
||||||
{
|
{
|
||||||
rawptr ptr = FreeListAlloc(&FL_ALLOC, size);
|
rawptr ptr = FLMemAlloc(size);
|
||||||
MemZero(ptr, size);
|
MemZero(ptr, size);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rawptr FLMemRealloc(rawptr old_ptr, usize size)
|
||||||
|
{
|
||||||
|
return FreeListRealloc(&FL_ALLOC, old_ptr, size);
|
||||||
|
}
|
||||||
|
|
||||||
static void FLMemFree(rawptr ptr)
|
static void FLMemFree(rawptr ptr)
|
||||||
{
|
{
|
||||||
FreeListFree(&FL_ALLOC, 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)
|
static void FreeListInit(FLAlloc *alloc, usize size)
|
||||||
{
|
{
|
||||||
alloc->lists = pMemAllocZeroed(sizeof(FreeList *) * 16);
|
alloc->list_head = pMemAllocZeroed(sizeof(FreeList));
|
||||||
alloc->list_count = 1;
|
|
||||||
alloc->list_capacity = 16;
|
|
||||||
alloc->nil = &FL_NIL_NODE;
|
alloc->nil = &FL_NIL_NODE;
|
||||||
alloc->grow_size = size;
|
alloc->grow_size = size;
|
||||||
|
|
||||||
_FreeListInit(&alloc->lists[0], size);
|
_FreeListInit(&alloc->list_head, size);
|
||||||
|
|
||||||
FreeListFreeAll(alloc);
|
FreeListFreeAll(alloc);
|
||||||
}
|
}
|
||||||
@ -243,29 +287,30 @@ static void _FreeListInit(FreeList **alloc, usize size)
|
|||||||
(*alloc)->data = (rawptr)(((uintptr)*alloc) + ((uintptr)sizeof(FreeList)));
|
(*alloc)->data = (rawptr)(((uintptr)*alloc) + ((uintptr)sizeof(FreeList)));
|
||||||
(*alloc)->size = size;
|
(*alloc)->size = size;
|
||||||
(*alloc)->used = sizeof(FreeList);
|
(*alloc)->used = sizeof(FreeList);
|
||||||
|
(*alloc)->next = &FL_NIL_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FreeListFreeAll(FLAlloc *alloc)
|
static void FreeListFreeAll(FLAlloc *alloc)
|
||||||
{
|
{
|
||||||
TicketMutLock(&alloc->mut);
|
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++)
|
next = current->next;
|
||||||
{
|
pMemFree(current, current->size);
|
||||||
pMemFree(alloc->lists[i], alloc->lists[i]->size);
|
current = next;
|
||||||
alloc->lists[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
alloc->list_count = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FLNode *node = (FLNode *)alloc->lists[0]->data;
|
current = alloc->list_head;
|
||||||
node->size = alloc->lists[0]->size;
|
|
||||||
|
FLNode *node = (FLNode *)current->data;
|
||||||
|
node->size = current->size;
|
||||||
node->next = &FL_NIL_NODE;
|
node->next = &FL_NIL_NODE;
|
||||||
|
|
||||||
alloc->lists[0]->head = node;
|
current->head = node;
|
||||||
alloc->lists[0]->used = sizeof(FreeList);
|
current->used = sizeof(FreeList);
|
||||||
|
|
||||||
TicketMutUnlock(&alloc->mut);
|
TicketMutUnlock(&alloc->mut);
|
||||||
}
|
}
|
||||||
@ -300,30 +345,35 @@ static FLNode *FreeListSearch(FreeList *alloc, usize size, usize alignment, usiz
|
|||||||
/*
|
/*
|
||||||
* NOT SAFE TO CALL OUTSIDE OF FreeListAlloc
|
* 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;
|
usize grow_size = alloc->grow_size;
|
||||||
if (alloc_size > grow_size)
|
if (alloc_size > grow_size)
|
||||||
grow_size += alloc_size;
|
grow_size += alloc_size;
|
||||||
|
|
||||||
_FreeListInit(&alloc->lists[i], grow_size);
|
FreeList *list = NULL;
|
||||||
|
|
||||||
FLNode *node = (FLNode *)alloc->lists[i]->data;
|
_FreeListInit(&list, grow_size);
|
||||||
node->size = alloc->lists[i]->size;
|
|
||||||
|
FLNode *node = (FLNode *)list->data;
|
||||||
|
node->size = list->size;
|
||||||
node->next = alloc->nil;
|
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)
|
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)
|
static rawptr FreeListAllocAlign(FLAlloc *alloc, usize size, usize alignment)
|
||||||
{
|
{
|
||||||
if (!FL_GLOBAL_INIT)
|
|
||||||
{
|
|
||||||
GlobalFreeListInit(FL_GLOBAL_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
TicketMutLock(&alloc->mut);
|
TicketMutLock(&alloc->mut);
|
||||||
|
|
||||||
FreeList *fl = NULL;
|
FreeList *fl = &FL_NIL_LIST;
|
||||||
for (u32 i = 0; i < alloc->list_count; i++)
|
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)
|
if (size < remaining)
|
||||||
{
|
{
|
||||||
fl = alloc->lists[i];
|
fl = current;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fl == NULL)
|
if (fl == &FL_NIL_LIST)
|
||||||
{
|
{
|
||||||
FreeListGrow(alloc, size);
|
fl = FreeListGrow(alloc, size);
|
||||||
fl = alloc->lists[alloc->list_count-1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rawptr ptr = _FreeListAllocAlign(fl, size, alignment);
|
rawptr ptr = _FreeListAllocAlign(fl, size, alignment);
|
||||||
@ -406,6 +453,25 @@ static rawptr FreeListAllocAlign(FLAlloc *alloc, usize size, usize alignment)
|
|||||||
return ptr;
|
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)
|
static void _FreeListFree(FreeList *alloc, rawptr ptr)
|
||||||
{
|
{
|
||||||
FLAllocHeader *header = cast(FLAllocHeader *, u8ptr(ptr) - sizeof(FLAllocHeader));
|
FLAllocHeader *header = cast(FLAllocHeader *, u8ptr(ptr) - sizeof(FLAllocHeader));
|
||||||
@ -438,16 +504,10 @@ static void FreeListFree(FLAlloc *alloc, rawptr ptr)
|
|||||||
|
|
||||||
TicketMutLock(&alloc->mut);
|
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);
|
_FreeListFree(list, 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TicketMutUnlock(&alloc->mut);
|
TicketMutUnlock(&alloc->mut);
|
||||||
|
|||||||
@ -75,18 +75,17 @@ typedef struct FLNode
|
|||||||
|
|
||||||
typedef struct FreeList
|
typedef struct FreeList
|
||||||
{
|
{
|
||||||
rawptr data;
|
rawptr data;
|
||||||
FLNode *head;
|
FLNode *head;
|
||||||
usize size;
|
usize size;
|
||||||
usize used;
|
usize used;
|
||||||
|
struct FreeList *next;
|
||||||
} FreeList;
|
} FreeList;
|
||||||
|
|
||||||
typedef struct FLAlloc
|
typedef struct FLAlloc
|
||||||
{
|
{
|
||||||
FreeList **lists;
|
FreeList *list_head;
|
||||||
TicketMut mut;
|
TicketMut mut;
|
||||||
u32 list_count;
|
|
||||||
u32 list_capacity;
|
|
||||||
FLNode *nil;
|
FLNode *nil;
|
||||||
usize grow_size;
|
usize grow_size;
|
||||||
} FLAlloc;
|
} FLAlloc;
|
||||||
@ -94,18 +93,22 @@ typedef struct FLAlloc
|
|||||||
static void GlobalFreeListInit(usize size);
|
static void GlobalFreeListInit(usize size);
|
||||||
static rawptr FLMemAlloc(usize size);
|
static rawptr FLMemAlloc(usize size);
|
||||||
static rawptr FLMemAllocZeroed(usize size);
|
static rawptr FLMemAllocZeroed(usize size);
|
||||||
|
static rawptr FLMemRealloc(rawptr old_ptr, usize size);
|
||||||
static void FLMemFree(rawptr ptr);
|
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 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 FreeListAllocAlign(FLAlloc *alloc, usize size, usize alignment);
|
||||||
static rawptr FreeListAlloc(FLAlloc *alloc, usize size);
|
static rawptr FreeListAlloc(FLAlloc *alloc, usize size);
|
||||||
static void _FreeListFree(FreeList *alloc, rawptr ptr);
|
|
||||||
static void FreeListFree(FLAlloc *alloc, rawptr ptr);
|
static void FreeListFree(FLAlloc *alloc, rawptr ptr);
|
||||||
static void FreeListFreeAll(FLAlloc *alloc);
|
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 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 FreeListCoalescence(FreeList *alloc, FLNode *prev_node, FLNode *free_node);
|
||||||
static void FreeListRemove(FLNode **head, FLNode *prev_node, FLNode *del_node);
|
static void FreeListRemove(FLNode **head, FLNode *prev_node, FLNode *del_node);
|
||||||
static void FreeListInsert(FLNode **head, FLNode *prev_node, FLNode *new_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