kernel: initial <512 byte object only slab

This commit is contained in:
Matheus
2023-04-18 22:22:08 -03:00
parent 156161e3aa
commit f9d1c046b7
3 changed files with 152 additions and 0 deletions
+2
View File
@@ -7,6 +7,7 @@
#include <kernel/pmm.h>
#include <arch/mmu.h>
#include <kernel/vmm.h>
#include <kernel/slab.h>
static cpu_t bsp_cpu;
@@ -21,5 +22,6 @@ void kernel_entry() {
logging_sethook(term_putchar);
arch_mmu_init();
vmm_init();
slab_init();
__assert(!"kernel entry end");
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef _SLAB_H
#define _SLAB_H
#include <stddef.h>
#include <stdint.h>
typedef struct slab_t {
struct slab_t *next;
struct slab_t *prev;
size_t used;
void **free;
} slab_t;
typedef struct scache_t {
// TODO lock
void (*ctor)(struct scache_t *cache, void *obj);
void (*dtor)(struct scache_t *cache, void *obj);
slab_t *full;
slab_t *partial;
slab_t *empty;
size_t size;
size_t truesize;
size_t alignment;
size_t slabobjcount;
} scache_t;
void slab_init();
#endif
+121
View File
@@ -0,0 +1,121 @@
#include <kernel/slab.h>
#include <kernel/vmm.h>
#include <logging.h>
#include <util.h>
#define SLAB_INDIRECT_CUTOFF 512
#define SLAB_INDIRECT_COUNT 16
#define SLAB_PAGE_OFFSET (PAGE_SIZE - sizeof(slab_t))
#define SLAB_DATA_SIZE SLAB_PAGE_OFFSET
#define GET_SLAB(x) (slab_t *)(ROUND_DOWN((uintptr_t)x, PAGE_SIZE) + SLAB_PAGE_OFFSET)
// the cache responsible for allocating all others
static scache_t selfcache = {
.size = sizeof(scache_t),
.alignment = 8,
.truesize = ROUND_UP(sizeof(scache_t) + sizeof(void **), 8),
.slabobjcount = SLAB_DATA_SIZE / ROUND_UP(sizeof(scache_t) + sizeof(void **), 8)
};
static scache_t *slabcache;
static void initsmall(scache_t *cache, slab_t *slab, void *base) {
slab->free = NULL;
slab->used = 0;
for (uintmax_t offset = 0; offset < cache->truesize * cache->slabobjcount; offset += cache->truesize) {
if (cache->ctor)
cache->ctor(cache, (void *)((uintptr_t)base + offset));
void **freenext = (void **)((uintptr_t)base + offset + cache->size);
*freenext = slab->free;
slab->free = freenext;
}
}
static bool growcache(scache_t *cache) {
__assert(cache->size < SLAB_INDIRECT_CUTOFF); // TODO bigger than this allocation and support
void *_slab = vmm_map(NULL, PAGE_SIZE, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAG_READ | ARCH_MMU_FLAG_WRITE | ARCH_MMU_FLAG_NOEXEC, NULL);
if (_slab == NULL)
return false;
slab_t *slab = GET_SLAB(_slab);
initsmall(cache, slab, _slab);
slab->next = cache->empty;
cache->empty = slab;
return true;
}
static void *takeobject(scache_t *cache, slab_t *slab) {
if (slab->free == NULL)
return NULL;
void *objend = slab->free;
slab->free = *slab->free;
slab->used += 1;
return (void *)((uintptr_t)objend - cache->size);
}
void *slab_allocate(scache_t *cache) {
// TODO lock
slab_t *slab = NULL;
if (cache->partial != NULL)
slab = cache->partial;
else if (cache->empty != NULL)
slab = cache->empty;
void *ret = NULL;
if (slab == NULL) {
if (growcache(cache))
slab = cache->empty;
else
goto cleanup;
}
ret = takeobject(cache, slab);
if (slab == cache->empty) {
cache->empty = slab->next;
slab->next = cache->partial;
cache->partial = slab;
}
if (slab->used == cache->slabobjcount) {
cache->partial = slab->next;
slab->next = cache->full;
cache->full = slab;
}
cleanup:
// TODO unlock
return ret;
}
scache_t *slab_newcache(size_t size, size_t alignment, void (*ctor)(scache_t *, void *), void (*dtor)(scache_t *, void *)) {
if (alignment == 0)
alignment = 8;
scache_t *cache = slab_allocate(&selfcache);
if (cache == NULL)
return NULL;
cache->size = size;
cache->alignment = alignment;
cache->truesize = ROUND_UP(size + sizeof(void **), alignment);
cache->ctor = ctor;
cache->dtor = dtor;
cache->slabobjcount = size < SLAB_INDIRECT_CUTOFF ? SLAB_DATA_SIZE / cache->truesize : SLAB_INDIRECT_COUNT;
printf("slab: new cache: size %lu align %lu truesize %lu objcount %lu\n", cache->size, cache->alignment, cache->truesize, cache->slabobjcount);
return cache;
}
void slab_init() {
slabcache = slab_newcache(sizeof(slab_t), 0, NULL, NULL);
__assert(slabcache);
}