From 832836d010bf68d13dd5e2bee8e60fe2098dc89b Mon Sep 17 00:00:00 2001 From: Matheus Date: Mon, 5 Jan 2026 18:14:33 -0300 Subject: [PATCH] lib: add generic resource allocator --- kernel-src/include/resource_allocator.h | 28 +++++++++++ kernel-src/lib/resource_allocator.c | 62 +++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 kernel-src/include/resource_allocator.h create mode 100644 kernel-src/lib/resource_allocator.c diff --git a/kernel-src/include/resource_allocator.h b/kernel-src/include/resource_allocator.h new file mode 100644 index 00000000..2b867c40 --- /dev/null +++ b/kernel-src/include/resource_allocator.h @@ -0,0 +1,28 @@ +#ifndef _RESOURCE_ALLOCATOR_H +#define _RESOURCE_ALLOCATOR_H + +// simple FIFO allocator for an arbritary resource + +#include +#include + +// TODO move this to a proper dequeue abstraction +typedef struct resource_allocator_waiter_t { + size_t requested; + thread_t *thread; + struct resource_allocator_waiter_t *next; +} resource_allocator_waiter_t; + +typedef struct { + mutex_t mutex; + resource_allocator_waiter_t *queue; + resource_allocator_waiter_t *tail; + size_t resource_current; + size_t allocate_max; +} resource_allocator_t; + +void resource_allocator_init(resource_allocator_t *allocator, size_t resource_total, size_t allocate_max); +void resource_allocate(resource_allocator_t *allocator, size_t count); +void resource_free(resource_allocator_t *allocator, size_t count); + +#endif diff --git a/kernel-src/lib/resource_allocator.c b/kernel-src/lib/resource_allocator.c new file mode 100644 index 00000000..fd383767 --- /dev/null +++ b/kernel-src/lib/resource_allocator.c @@ -0,0 +1,62 @@ +#include +#include + +static void insert(resource_allocator_t *allocator, resource_allocator_waiter_t *node) { + if (allocator->queue) { + allocator->tail->next = node; + allocator->tail = node; + } else { + allocator->queue = node; + allocator->tail = node; + } +} + +static void pop(resource_allocator_t *allocator) { + resource_allocator_waiter_t *w = allocator->queue; + allocator->queue = w->next; + sched_wakeup(w->thread, 0); +} + +void resource_allocator_init(resource_allocator_t *allocator, size_t resource_total, size_t allocate_max) { + MUTEX_INIT(&allocator->mutex); + allocator->queue = allocator->tail = NULL; + allocator->resource_current = resource_total; + allocator->allocate_max = allocate_max; +} + +void resource_allocate(resource_allocator_t *allocator, size_t count) { + MUTEX_ACQUIRE(&allocator->mutex); + + if (allocator->queue || allocator->resource_current < count) { + resource_allocator_waiter_t waiter = { + .requested = count, + .thread = current_thread(), + .next = NULL + }; + + insert(allocator, &waiter); + sched_prepare_sleep(false); + MUTEX_RELEASE(&allocator->mutex); + sched_yield(); + return; + } + + allocator->resource_current -= count; + + MUTEX_RELEASE(&allocator->mutex); +} + +void resource_free(resource_allocator_t *allocator, size_t count) { + count = min(allocator->allocate_max, count); + MUTEX_ACQUIRE(&allocator->mutex); + + allocator->resource_current += count; + + while (allocator->queue && allocator->queue->requested <= allocator->resource_current) { + allocator->resource_current -= allocator->queue->requested; + + pop(allocator); + } + + MUTEX_RELEASE(&allocator->mutex); +}