From d583dbaced92e0d03d556e11fd1713644b55b0d9 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 8 Sep 2025 05:03:40 +0200 Subject: [PATCH] Initial implementation of a freelist. blocks contain a header --- Makefile | 1 + kern/libkern/freelist.c | 117 ++++++++++++++++++++++++++++++++++++++++ kern/libkern/freelist.h | 34 ++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 kern/libkern/freelist.c create mode 100644 kern/libkern/freelist.h diff --git a/Makefile b/Makefile index 3fbba85..b316fc2 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,7 @@ quickstart: KERNEL_OBJ := \ kern/entry.o \ kern/start.o \ + kern/libkern/freelist.o \ kern/libkern/string.o \ kern/libkern/proc.o \ kern/libkern/uart.o \ diff --git a/kern/libkern/freelist.c b/kern/libkern/freelist.c new file mode 100644 index 0000000..cba0b1f --- /dev/null +++ b/kern/libkern/freelist.c @@ -0,0 +1,117 @@ +#include "freelist.h" +#include "stddef.h" +#include +#include +#include +#include + +/* Fiddle these around according to your need. */ +#ifdef FREELIST_NOALIGN +#define ALIGN(x) (x) +#else // FREELIST_NOALIGN + +/* Align to nearest multiple of sizeof(void*) */ +static inline size_t align_up(size_t n) { + return (n + sizeof(void *) - 1) & ~(sizeof(void *) - 1); +} + +#define ALIGN(x) (align_up(x)) +#endif // FREELIST_NOALIGN + +/* Initialize the FreeList */ +int fl_init(FreeList *fl, uintptr_t start, uintptr_t end, size_t itemsize) { + size_t size = ALIGN(itemsize + sizeof(FreeListBlock)); + + if (!fl || end <= start) + return EXIT_FAILURE; + + fl->start = start; + fl->end = end; + fl->size = size; + fl->allocated = 0; + + FreeListBlock *block = (FreeListBlock *)start; + for (size_t i = 0; i < fl_capacity(fl); i++) { + block->next = (FreeListBlock *)((void *)block + size); + block->block_state = FL_FREE; + block = block->next; + } + + block->next = NULL; + + fl->free = (FreeListBlock *)start; + return EXIT_SUCCESS; +} + +/* Allocate some memory from the FreeList */ +void *fl_alloc(FreeList *fl) { + if (!fl->free || fl->free->block_state != FL_FREE) + return NULL; + + FreeListBlock *m = fl->free; + m->block_state = FL_USED; + + fl->free = fl->free->next; + fl->allocated++; + + return ((void *)m) + sizeof(FreeListBlock); +} + +/* Return some memory to the FreeList */ +int fl_free(FreeList *fl, void *ptr) { + if (!fl_is_managed(fl, ptr)) { + return EXIT_FAILURE; /* We cant free memory we do not own */ + } + + FreeListBlock *block = (FreeListBlock *)((uintptr_t)ptr - sizeof(FreeListBlock)); + + if (block->block_state != FL_USED) { + return EXIT_FAILURE; /* Block must be used */ + } + + block->block_state = FL_FREE; + block->next = fl->free; + fl->free = block; + fl->allocated--; + + return EXIT_SUCCESS; +} + +/* Returns how many slots are occupied */ +size_t fl_allocated(FreeList *fl) { + return fl->allocated; +} + +/* Returns how many free slots are available (O(1)) */ +size_t fl_available(FreeList *fl) { + return fl_capacity(fl) - fl->allocated; +} + +/* Returns the total amount of items the freelist will hold */ +size_t fl_capacity(FreeList *fl) { + return (fl->end - fl->start) / fl->size; +} + +/* Check if a piece of memory is managed by the FreeList */ +int fl_is_managed(FreeList *fl, void *ptr) { + return ((uintptr_t)ptr >= fl->start && (uintptr_t)ptr < fl->end); +} + +/* Returns the ratio of metadata versus data as a scalar in range 0..1 */ +float fl_utilization(FreeList *fl, size_t itemsize) { + return (float)itemsize / fl->size; +} + +/* Walks the free pages/slots, returns total count (O(n), given no cycles) */ +size_t fl_check(FreeList *fl) { + int avail = 0; + FreeListBlock *cursor = fl->free; + + while (cursor->next != NULL) { + avail++; + assert(cursor->block_state == FL_FREE); + cursor = cursor->next; + } + + return avail; +} diff --git a/kern/libkern/freelist.h b/kern/libkern/freelist.h new file mode 100644 index 0000000..885b58a --- /dev/null +++ b/kern/libkern/freelist.h @@ -0,0 +1,34 @@ +#ifndef FREELIST_H +#define FREELIST_H + +#include +#include +#include + +#define FL_FREE ((uint8_t)0x00) +#define FL_USED ((uint8_t)0x01) + +typedef struct FreeListBlock { + struct FreeListBlock *next; + uint8_t block_state; +} FreeListBlock; + +typedef struct { + uintptr_t start; + uintptr_t end; + FreeListBlock *free; + size_t size; + size_t allocated; +} FreeList; + +int fl_init(FreeList *fl, uintptr_t start, uintptr_t end, size_t itemsize); +int fl_free(FreeList *fl, void *ptr); +int fl_is_managed(FreeList *fl, void *ptr); +void *fl_alloc(FreeList *fl); +size_t fl_check(FreeList *fl); +size_t fl_allocated(FreeList *fl); +size_t fl_available(FreeList *fl); +size_t fl_capacity(FreeList *fl); +float fl_utilization(FreeList *fl, size_t itemsize); + +#endif // FREELIST_H