Simple slot allocator
This commit is contained in:
@@ -1,112 +1,79 @@
|
||||
#ifndef UC_SLOT_ALLOCATOR_H_
|
||||
#define UC_SLOT_ALLOCATOR_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "ucore/bitvec.h"
|
||||
#include <assert.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;
|
||||
// Repurpose free memory to eep a linked list of free slots
|
||||
typedef struct UCSlot UCSlot;
|
||||
struct UCSlot {
|
||||
UCSlot *next;
|
||||
};
|
||||
|
||||
typedef struct UCSlotArena UCSlotArena;
|
||||
struct UCSlotArena {
|
||||
UCSlot *free_list;
|
||||
uint8_t *memory_start;
|
||||
size_t memory_len;
|
||||
size_t n_slots;
|
||||
size_t slot_size;
|
||||
};
|
||||
|
||||
/** 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
|
||||
/**
|
||||
* Initialize a memory arena for dynamically allocating slots of memory.
|
||||
* Each allocation returns memory slots of the same size
|
||||
* Note: For max speed, align @memory and @slot_size to the size of a pointer
|
||||
*
|
||||
* @param arena arena to initialize
|
||||
* @param memory start of the backing memory
|
||||
* @param memory_len length of @memory
|
||||
* @param slot_size size of each slot allocation
|
||||
*/
|
||||
#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 \
|
||||
};
|
||||
static inline void uc_slot_arena_init(UCSlotArena *arena, void *memory, size_t memory_len, size_t slot_size)
|
||||
{
|
||||
// Optionally - align to a pointer
|
||||
//slot_size = (slot_size + _Alignof(UCSlot) - 1) & (~(_Alignof(UCSlot) - 1));
|
||||
assert(slot_size >= sizeof(UCSlot));
|
||||
size_t n_slots = memory_len / slot_size;
|
||||
arena->free_list = NULL;
|
||||
|
||||
/** 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) \
|
||||
};
|
||||
uint8_t *start = (uint8_t *)memory;
|
||||
// build free_list in ascending order, anticipating sequential allocation
|
||||
// and sequential access as the common case
|
||||
for (size_t slot = n_slots; slot > 0; slot--) {
|
||||
size_t index = slot - 1;
|
||||
UCSlot *free_slot = (UCSlot *)(start + index * slot_size);
|
||||
free_slot->next = arena->free_list;
|
||||
arena->free_list = free_slot;
|
||||
}
|
||||
|
||||
/** 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
|
||||
arena->n_slots = n_slots;
|
||||
arena->memory_start = (uint8_t*)memory;
|
||||
arena->memory_len = memory_len;
|
||||
arena->slot_size = slot_size;
|
||||
}
|
||||
|
||||
static inline void *uc_slot_alloc(UCSlotArena *arena)
|
||||
{
|
||||
UCSlot *slot = arena->free_list;
|
||||
|
||||
if (slot != NULL) {
|
||||
arena->free_list = slot->next;
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
static inline void uc_slot_free(UCSlotArena *arena, void *mem)
|
||||
{
|
||||
if (mem != NULL) {
|
||||
assert((uint8_t *)mem >= arena->memory_start);
|
||||
assert((uint8_t *)mem < arena->memory_start + arena->memory_len);
|
||||
|
||||
UCSlot *slot = (UCSlot *)mem;
|
||||
slot->next = arena->free_list;
|
||||
arena->free_list = slot;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user