#ifndef UC_SLOT_ALLOCATOR_H_ #define UC_SLOT_ALLOCATOR_H_ #include #include #include "ucore/bitvec.h" #ifdef __cplusplus extern "C" { #endif /** @file * Fixed size slot memory allocator * * UCSlotAlloc is used to allocate fixed slots of memory from a pre-allocated * piece of memory. * * The main use case is to keep allocated memory in a contiguous block for use * maximum number of objects(slots) is known and relatively small. More than 131072 slots * is not recommended. * * Note that this allocator is not thread safe. * * A bitmap is used to track which slots are allocated. */ typedef struct UCSlotAlloc UCSlotAlloc; struct UCSlotAlloc { const uint32_t slot_size; const uint32_t num_slots; struct UCBitVec bitmap; uint8_t *slots; }; /** Initialize a UCSlotAlloc with an array as the backing memory to allocate slots from. * The macro can be used at local scope to allocate memory automatic (stack) storage, * or at global scope where the backin array will have static storage duration * * Use as: * @code * UC_SLOT_ALLOC_DEF(my_allocator, sizeof foo, 1024) * struct foo *foo = uc_slot_alloc(&my_allocator); * if (foo == NULL) { * // out of memory * } else { * .. use foo * uc_slot_free(&my_allocator, foo); * } * @endcode * * @param var_name Variable name for the allocator * @param v slot_size Memory size allocated for each slot * @param v num_slots Number of slots to reserve memory for */ #define UC_SLOT_ALLOC_DEF(var_name, slot_size_, num_slots_) \ struct {\ uc_bv_integer bitmap[UC_BV_LEN((num_slots_))]; \ uint8_t memory[(num_slots_) * (slot_size_)] __attribute__((aligned)); \ } var_name ## _memory = { \ }; \ UCSlotAlloc var_name = { \ .slot_size = (slot_size_), \ .num_slots = (num_slots_), \ .bitmap = UC_BV_STATIC_INIT(var_name ## _memory.bitmap), \ .slots = var_name ## _memory.memory \ }; /** Similar to UC_SLOT_ALLOC_DEF but allows you to specify the backing memory that must * be atleast as large as num_slots * slot_size. Note that an array of num_slots * slot_size * bits is also allocated for the bitmap with this definition */ #define UC_SLOT_ALLOC_DEF_EX(var_name, slot_size_, num_slots_, memory) \ uc_bv_integer var_name ## _bitmap[UC_BV_LEN((num_slots_))] = {}; \ UCSlotAlloc var_name = { \ .slot_size = (slot_size_), \ .num_slots = (num_slots_), \ .bitmap = UC_BV_STATIC_INIT(var_name ## _bitmap), \ .slots = (memory) \ }; /** Allocate a memory slot * * @param sa The allocator to allocate from * @return A pointer to the memory slot that's sa.slot_size big, or NULL if * all slots are allocated */ void *uc_slot_alloc(UCSlotAlloc *sa); /** Free a memory slot previously returned from uc_slot_alloc() * * @param sa The allocator to free from. * @param slot The memory slot to free. Passing a NULL pointer is undefined behavior */ void uc_slot_free(UCSlotAlloc *restrict sa, void *restrict slot); /** uc_slot_free() where the slot can be a NULL pointer */ #define uc_slot_free_safe(sa, slot) \ do { \ if ((slot) != NULL) { \ uc_slot_free((sa), (slot)); \ } \ } while (0) #ifdef __cplusplus } #endif #endif