diff --git a/src/allocators.c b/src/allocators.c index 3f3dd2c..393d9a8 100644 --- a/src/allocators.c +++ b/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; - } - - 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); diff --git a/src/allocators.h b/src/allocators.h index 4ce9b50..d444507 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -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);