From 8d63b96ad929f4ff2607cc63a89cda4a537eb9a9 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 8 Sep 2026 15:16:44 +0200 Subject: [PATCH] feat: add FreeObj, Slab and spinLockInit --- src/slab.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ src/spinlock.c | 40 +++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 src/slab.c create mode 100644 src/spinlock.c diff --git a/src/slab.c b/src/slab.c new file mode 100644 index 0000000..59fcea8 --- /dev/null +++ b/src/slab.c @@ -0,0 +1,130 @@ +#include "slab.h" +#include "pmm.h" + +typedef struct FreeObj { + struct FreeObj* next; +} FreeObj; + +typedef struct Slab { + struct Slab* next; + FreeObj* freeList; + usize freeCount; +} Slab; + +static usize alignUp(usize value, usize alignment) +{ + return (value + alignment - 1) & ~(alignment - 1); +} + +static Slab* growSlab(KmemCache* cache) +{ + uint64 frame = pmmAlloc(); + if (frame == 0) + return nullptr; + + Slab* slab = (Slab*)frame; + slab->next = cache->slabs; + slab->freeCount = cache->objsPerSlab; + + uint8* base = (uint8*)frame + alignUp(sizeof(Slab), sizeof(void*)); + FreeObj* prev = nullptr; + for (usize i = 0; i < cache->objsPerSlab; i++) { + FreeObj* obj = (FreeObj*)(base + i * cache->objSize); + obj->next = prev; + prev = obj; + } + slab->freeList = prev; /* built back-to-front; order does not matter */ + + cache->slabs = slab; + cache->slabCount++; + return slab; +} + +bool kmemCacheInit(KmemCache* cache, const char* name, usize objSize) +{ + cache->name = name; + cache->slabs = nullptr; + cache->slabCount = 0; + cache->usedObjs = 0; + + usize size = objSize < sizeof(FreeObj) ? sizeof(FreeObj) : objSize; + size = alignUp(size, sizeof(void*)); + cache->objSize = size; + + usize headerSize = alignUp(sizeof(Slab), sizeof(void*)); + if (headerSize + size > frameSize) { + cache->objsPerSlab = 0; + return false; + } + cache->objsPerSlab = (frameSize - headerSize) / size; + return true; +} + +void kmemCacheDestroy(KmemCache* cache) +{ + Slab* slab = cache->slabs; + while (slab != nullptr) { + Slab* next = slab->next; + pmmFree((uint64)slab); + slab = next; + } + + cache->name = nullptr; + cache->objSize = 0; + cache->objsPerSlab = 0; + cache->slabs = nullptr; + cache->slabCount = 0; + cache->usedObjs = 0; +} + +void* kmemCacheAlloc(KmemCache* cache) +{ + if (cache->objsPerSlab == 0) + return nullptr; + + Slab* slab = cache->slabs; + while (slab != nullptr && slab->freeList == nullptr) + slab = slab->next; + + if (slab == nullptr) { + slab = growSlab(cache); + if (slab == nullptr) + return nullptr; + } + + FreeObj* obj = slab->freeList; + slab->freeList = obj->next; + slab->freeCount--; + cache->usedObjs++; + return (void*)obj; +} + +void kmemCacheFree(KmemCache* cache, void* obj) +{ + Slab* slab = (Slab*)((uintptr)obj & ~(uintptr)(frameSize - 1)); + FreeObj* fo = (FreeObj*)obj; + fo->next = slab->freeList; + slab->freeList = fo; + slab->freeCount++; + cache->usedObjs--; +} + +usize kmemCacheUsed(const KmemCache* cache) +{ + return cache->usedObjs; +} + +usize kmemCacheCapacity(const KmemCache* cache) +{ + return cache->slabCount * cache->objsPerSlab; +} + +usize kmemCacheSlabCount(const KmemCache* cache) +{ + return cache->slabCount; +} + +usize kmemCacheObjsPerSlab(const KmemCache* cache) +{ + return cache->objsPerSlab; +} diff --git a/src/spinlock.c b/src/spinlock.c new file mode 100644 index 0000000..86c11da --- /dev/null +++ b/src/spinlock.c @@ -0,0 +1,40 @@ +#include "spinlock.h" +#include "ports.h" + +void spinLockInit(SpinLock* lock) +{ + lock->locked = 0; +} + +uint64 spinLockAcquire(SpinLock* lock) +{ + uint64 flags = saveAndDisableInterrupts(); + while (__atomic_exchange_n(&lock->locked, 1, __ATOMIC_ACQUIRE) != 0) { + /* single-core: a lock held across this spin can only be released by + an interrupt handler, but interrupts are off -- callers must never + acquire a lock they (or a handler nested under them) already hold */ + } + return flags; +} + +bool spinLockTryAcquire(SpinLock* lock, uint64* savedFlags) +{ + uint64 flags = saveAndDisableInterrupts(); + if (__atomic_exchange_n(&lock->locked, 1, __ATOMIC_ACQUIRE) != 0) { + restoreInterrupts(flags); + return false; + } + *savedFlags = flags; + return true; +} + +void spinLockRelease(SpinLock* lock, uint64 flags) +{ + __atomic_store_n(&lock->locked, 0, __ATOMIC_RELEASE); + restoreInterrupts(flags); +} + +bool spinLockIsLocked(const SpinLock* lock) +{ + return __atomic_load_n(&lock->locked, __ATOMIC_ACQUIRE) != 0; +}