feat: add FreeObj, Slab and spinLockInit
This commit is contained in:
1 parent
730467ce1f
commit
8d63b96ad9
2 files changed
+170
No files matched your search
+130
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user