11 #define KB_FL_ALLOC_CONSISTENCY_CHECK 0
87 #define PTR_COMPARE(ptr1, offset1, op, ptr2, offset2) ((((u8 *) (ptr1)) + (offset1)) op(((u8 *) (ptr2)) + (offset2)))
90 entry->
size = data_size;
92 KB_TRACE(
"created free list with data size {usize} for head {pointer}", data_size, (
void *) entry);
100 KB_TRACE(
"trying to add entry with size {usize} at {pointer} to free list for head {pointer}",
113 KB_TRACE(
"adding new entry by merging with previous entry");
117 KB_TRACE(
"additionally merging with next entry");
126 KB_TRACE(
"adding new entry by merging with next entry");
133 at_entry->
next = entry;
136 KB_TRACE(
"adding new entry as part of the existing list");
137 previous->
next = at_entry;
139 KB_TRACE(
"adding new entry as new head of the list");
148 KB_TRACE(
"adding new entry at the end of the list");
151 previous->
next = at_entry;
158 KB_TRACE(
"trying to remove entry with size {usize} from free list for head {pointer}",
size, (
void *) head);
170 u8 *data_ptr = (
void *) (entry + 1);
179 KB_TRACE(
"did not find fitting entry in free list");
183 static void free_list_check_consistency(
const char *prefix,
struct free_list_entry *head) {
184 #if KB_FL_ALLOC_CONSISTENCY_CHECK == 1
185 KB_DEBUG(
"checking free list {pointer}", head);
189 KB_DEBUG(
"{16l:raw_string} entry at {10r:u64} with size {10r:usize} (entry:{pointer}, data:{pointer})",
191 ((u8 *) entry) - ((u8 *) head),
195 if (previous &&
PTR_COMPARE(previous + 1, previous->
size, >=, entry, 0)) {
196 KB_ASSERT(
false,
"inconsistent free list entry, size overlaps next entry");
250 usize block_size = 0;
254 KB_ERROR(
"could not allocate memory for free_list_allocator_block");
257 block_size -= header_offset;
258 block->
data = block + 1;
259 block->
size = block_size;
271 KB_ERROR(
"could not allocate memory for initial free_list_allocator_block");
279 alloc->
state = block;
280 KB_TRACE(
"created free_list_allocator with initial size {usize}",
size);
288 KB_TRACE(
"destroying free_list_allocator_block {pointer} and free_list {pointer}",
295 KB_TRACE(
"destroyed free_list_allocator");
303 free_list_check_consistency(
"pre-alloc", block->
free_list);
305 free_list_check_consistency(
"post-alloc-succ", block->
free_list);
312 KB_TRACE(
"did not find fitting block, creating new one");
313 usize new_size = prev_block->
size;
314 if (
size > new_size) {
316 "new block size {usize} is not enough for requested allocation of {usize} bytes, using the requested "
317 "size as new block size",
323 if (fitting_block ==
KB_NULL) {
324 KB_ERROR(
"could not allocate memory for free_list_allocator_block");
327 prev_block->
next = fitting_block;
328 KB_TRACE(
"created new block to hold {usize} bytes", new_size);
330 "a created block must be able to find space in its free list");
340 if (mem_tmp > (u8 *) block->
data && mem_tmp < (u8 *) block->
data + block->
size) {
341 free_list_check_consistency(
"pre-free", block->
free_list);
343 KB_WARN(
"free_list_allocator was not able to track freed memory, leaking memory until destruction");
345 free_list_check_consistency(
"post-free-succ", block->
free_list);
358 KB_TRACE(
"reset free_list_allocator");
void allocator_implementation(allocator *alloc, allocator_impl_destroy_fn destroy, allocator_impl_allocate_fn allocate, allocator_impl_free_fn free, allocator_impl_free_all_fn free_all)
Set allocator implementation.
Lightweight layer between platform and other engine components to enable tracing/monitoring.
#define UNUSED(x)
Mark parameter as unused.
#define KB_NULL
Value of an invalid ptr (nullptr).
void free_list_entry_create(free_list_entry *entry, usize data_size)
Initialize a free_list_list_entry for a block of a certain size.
b8 free_list_allocator_create(allocator *alloc, usize size)
#define PTR_COMPARE(ptr1, offset1, op, ptr2, offset2)
Compare two pointers with byte-wise offsets applied.
void free_list_allocator_free(allocator *alloc, void *mem, usize size)
b8 free_list_remove(free_list_entry **head, usize size, void **res)
Find a suitable offset for a requested size in the free list.
void free_list_allocator_block_destroy(free_list_allocator_block *block)
Destroy a free_list_allocator_block.
void * free_list_allocator_allocate(allocator *alloc, usize size)
b8 free_list_insert(free_list_entry **head, usize size, void *at)
Add a free_list_entry to the free list.
void free_list_allocator_free_all(allocator *alloc)
free_list_allocator_block * free_list_allocator_block_create(usize size, free_list_allocator_block *next)
Create a new free_list_allocator_block.
struct free_list_entry free_list_entry
A single entry of a free list.
void free_list_allocator_destroy(allocator *alloc)
struct free_list_allocator_block free_list_allocator_block
Internal state of the free_list_allocator.
Function signatures for free list based allocator implementation.
#define KB_DEBUG(...)
Log entry with debug log level.
#define KB_ASSERT(expr,...)
Perform runtime assertion and log failures.
#define KB_WARN(...)
Log entry with warn log level.
#define KB_ERROR(...)
Log entry with error log level.
#define KB_TRACE(...)
Log entry with trace log level.
Central allocator structure.
void * state
Type specific state of the allocator.
Internal state of the free_list_allocator.
usize size
Size in bytes of the usable data block.
free_list_entry * free_list
Pointer to free list.
void * data
Pointer to beginning of managed block.
struct free_list_allocator_block * next
Pointer to the next block in the linked list.
A single entry of a free list.
struct free_list_entry * next
Pointer to the next entry in the free list.
usize size
The size in bytes of the free space in the associsated memory block.