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