summaryrefslogblamecommitdiffstats
path: root/memory/slab.c
blob: dc8aeda362b06de4a51a830601450711e9a05d42 (plain) (tree)
1
2
3
4
5
6
7
                 
                 
                   



                        












                                                                       

                                              
 
                                                          

                                                             

                                         
                                        
                             
                                            



                                                       

                                                                           

                              
                                      
 
                       














                                                          
                                                              


                                                       
                            














                                               
                               

                      
                        



















                                                                
                                         


                                                      
                                         



                                                       
                                                













                                                                     
                                            



                                                       
                                                








                                                                     
                                                             






                                             
#include "slab.h"
#include "bump.h"
#include "memory.h"
#include "string.h"
#include "jove.h"
#include "print.h"
#include "klib/format.h"

static int
s_get_free_listw(size_t slabw, size_t objw)
{
    int freelistc = 1;
    while(freelistc < 256) {
        int maxobjc = (slabw - (freelistc * sizeof(uintptr_t))) / objw;
        if(maxobjc <= freelistc) return maxobjc;
        freelistc++;
    }
    return freelistc;
}

static slab_t
*s_slab_new(slab_cache_t *cache, slab_t *last)
{
    size_t slab_width = (cache->slab_pages << PAGE_SHIFT);
    uintptr_t descr_base = (uintptr_t)bump_alloc(slab_width);
    slab_t *descr = (slab_t*)descr_base;

    size_t free_listc = s_get_free_listw(
            slab_width - sizeof(slab_t),
            cache->obj_size);
    size_t descriptor_width = sizeof(slab_t)
        + (free_listc * sizeof(uintptr_t));
    uintptr_t obj_base = descr_base + descriptor_width;

    if(free_listc < 8) {
        free_listc = ((slab_width - sizeof(slab_t)) / cache->obj_size);
        descr = kmalloc(sizeof(slab_t) + (free_listc * sizeof(uintptr_t)));
        obj_base = descr_base;
    }
    cache->obj_capacity += free_listc;

    *descr = (slab_t) {
        .prev = last,
        .next = (last == NULL ? NULL : last->next),
        .slab_base = (void*)descr_base,
        .obj_base = (void*)obj_base,
        .free_count = free_listc,
        .free_index = free_listc - 1
    };
    for(size_t i = 0; i < free_listc; i++) {
        descr->free[i] = obj_base + (i * cache->obj_size);
    }

    return descr;
}

void
slabcache_new(slab_cache_t *cache, char *name, size_t objsize)
{
    if(objsize % 8 > 0) objsize += (8 - (objsize % 8));
    size_t pages = objsize > 512 ? (objsize >> 9) : 1;
    *cache = (slab_cache_t){
        .obj_size = objsize,
        .slab_pages = pages,
        .list_free = NULL,
        .list_partial = NULL,
        .list_full = NULL
    };
    size_t namelen = strlen(name);
    namelen = namelen > 32 ? 32 : namelen;
    memcpy(cache->name, name, namelen);

    //Allocate the first slab
    cache->list_free = s_slab_new(cache, NULL);
}

void*
slab_alloc(slab_cache_t *cache)
{
    // Get a free slab
    slab_t *slab = NULL;
    if(cache->list_partial != NULL) slab = cache->list_partial;
    if(slab == NULL && cache->list_free != NULL) {
        slab = cache->list_free;
        cache->list_free = slab->next;
    }
    if(slab == NULL) slab = s_slab_new(cache, cache->list_free);
    cache->list_partial = slab;

    // Take an object from the slab.
    uintptr_t objaddr = slab->free[slab->free_index];
    slab->free_index -= 1;

    if(slab->free_index < 0) {
        slab->next = cache->list_full;
        cache->list_full = slab;
    }
    return (void*)objaddr;
}

void
slab_free(slab_cache_t *cache, void *ptr)
{
    uintptr_t addr = (uintptr_t)ptr;
    //Look for the pointer in the bounds of every slab
    for(slab_t *slab = cache->list_full; 
            slab != NULL; slab = slab->next)
    {
        uintptr_t base = (uintptr_t)slab->obj_base;
        uintptr_t limit = ((uintptr_t)slab->slab_base) 
            + (cache->slab_pages << PAGE_SHIFT);
        if(addr > limit || addr < base) continue;
        if((addr - base) % cache->obj_size != 0) {
            klogf("Tried to free offset pointer %#016X in slab %s\n",
                    addr, cache->name);
            return;
        }
        slab->free_index++;
        slab->free[slab->free_index] = addr;

        cache->list_full = slab->next;
        slab->next = cache->list_partial;
        cache->list_partial = slab;
        return;
    }
    for(slab_t *slab = cache->list_partial; 
            slab != NULL; slab = slab->next)
    {
        uintptr_t base = (uintptr_t)slab->obj_base;
        uintptr_t limit = ((uintptr_t)slab->slab_base) 
            + (cache->slab_pages << PAGE_SHIFT);
        if(addr > limit || addr < base) continue;
        if((addr - base) % cache->obj_size != 0) {
            klogf("Tried to free offset pointer %#016X in slab %s\n",
                    addr, cache->name);
            return;
        }
        slab->free_index++;
        slab->free[slab->free_index] = addr;

        if(slab->free_index == ((int)slab->free_count - 1)) {
            cache->list_partial = slab->next;
            slab->next = cache->list_free;
            cache->list_free = slab;
        }
        return;
    }
}