131 lines
2.9 KiB
C
131 lines
2.9 KiB
C
#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;
|
|
}
|