slab.h

back


#ifndef _SLAB_H_INCLUDED
#define _SLAB_H_INCLUDED

#include <stddef.h>
#include <stdint.h>

#include <mm/bitmap.h>

// Type for indexing objects in a Slab region
typedef uint16_t SlabIndexType;

// Header of a Slab region
typedef struct {
    // Size of objects in this region
    uint16_t      allocation_size;

    // Number of objects in this region
    SlabIndexType num_entries;

    // Size of the bitmap in bytes
    uint32_t      bitmap_size;
} SlabHeader;

/*
 * Initialize a new slab allocator at the given memory location. After initialization,
 * you can use mem_start as pointer to SlabHeader for more operations.
 *
 * @param mem_start       Memory address where the slab allocator region begins
 * @param mem_end         Memory address where the slab allocator region ends
 * @param allocation_size Size of single objects in this allocator
 */
void init_slab(uint32_t mem_start, uint32_t mem_end, size_t allocation_size);

/*
 * Calculate the overhead of a given slab allocator.
 *
 * @param   slab Pointer to SlabHeader to calculate overhead.
 * @returns Allocator overhead in bytes.
 */
static inline size_t slab_overhead(const SlabHeader* slab) {
    size_t overhead = sizeof(SlabHeader) + slab->bitmap_size;
    return overhead + (slab->allocation_size - (overhead % slab->allocation_size));
}

/*
 * Calculate memory address for a given allocator and index
 *
 * @param slab Pointer to SlabHeader for calculation
 * @param idx  Index of the object in the allocator
 * @returns Memory address of the object
 */
static inline uint32_t slab_mem(const SlabHeader* slab, const SlabIndexType idx) {
    return (idx * slab->allocation_size) + slab_overhead(slab) + (uint32_t)slab;
}

/*
 * Calculate index for a given memory address in a given allocator
 *
 * @param slab Pointer to SlabHeader for calculation
 * @param mem  Memory address to calculate index
 * @returns    Index of the given memory address in the allocator
 */
static inline SlabIndexType slab_index(const SlabHeader* slab, const uint32_t mem) {
    return (mem - slab_overhead(slab) - (uint32_t)slab) / slab->allocation_size;
}

/*
 * Allocate object from slab allocator region.
 *
 * @param   slab mem_start given to init_slab before
 * @returns Address in memory with the allocated object, NULL if full
 */
static inline uint32_t slab_alloc(SlabHeader* slab) {
    bitmap_t bitmap = (bitmap_t)((uint32_t)slab + sizeof(SlabHeader));

    SlabIndexType idx;
    for(idx = 0; idx < slab->num_entries && bitmap_get(bitmap, idx); ++idx);

    if(idx < slab->num_entries) {
        bitmap_set(bitmap, idx);
        return slab_mem(slab, idx);
    }
    return 0;
}

/*
 * Free object in slab allocator region.
 *
 * @param slab   mem_start given to init_slab before
 * @param memory Address to mark as free
 */
static inline void slab_free(SlabHeader* slab, uint32_t mem) {
    bitmap_t bitmap = (bitmap_t)((uint32_t)slab + sizeof(SlabHeader));
    bitmap_clear(bitmap, slab_index(slab, mem));
}

#endif