/* * KPL memory allocator */ typedef enum : int32_t { KPL_MEMORY_ALLOCATOR_MIN_SIZE_POW2 = 5, KPL_MEMORY_ALLOCATOR_MIN_ROUND_SIZE_POW2 = KPL_MEMORY_ALLOCATOR_MIN_SIZE_POW2 - 1, KPL_MEMORY_ALLOCATOR_MAX_SIZE_POW2 = 22, KPL_MEMORY_ALLOCATOR_SLAB_COUNT = KPL_MEMORY_ALLOCATOR_MAX_SIZE_POW2 + 1 } kpl_memory_allocator_enum; /* * Each slab is a linked list allocated with calloc and free * *buffer is allocated with mmap */ typedef struct _kpl_memory_allocator_slab { uint32_t buffer_size, buffer_used; struct _kpl_memory_allocator_slab *slab_next; uint8_t *buffer; } kpl_memory_allocator_slab; /* * Each group only allocates for a single power of two */ typedef struct { int32_t slab_size_pow2; kpl_memory_allocator_slab *slab_head, *slab_tail; kpl_object_queue object_pool; } kpl_memory_allocator_slab_group; /* * The allocator allocates object rounded to the next power of two * We first check if the pool has objects, then bump allocate off the slab *buffer * Each slab is only responsible for one power of two, all objects in buffer and pool are of the same size * The memory is allocated from buffer and returned to the pool * The slabs and buffers are freed and returned to the system at once on allocator free * The object pools are from each mapped buffer, they do not need to be freed */ typedef struct { kpl_memory_allocator_slab_group slabs[KPL_MEMORY_ALLOCATOR_SLAB_COUNT]; } kpl_memory_allocator; /* * Called by owner thread */ void kpl_memory_allocator_init(kpl_memory_allocator *memory_allocator); /* * Called by owner thread */ void kpl_memory_allocator_free(kpl_memory_allocator *memory_allocator); /* * Only call this though kpl_thread_object_allocate * All allocations must extend the KPL_OBJECT_HEADER */ void *kpl_memory_allocator_allocate(kpl_memory_allocator *memory_allocator, int32_t size, int32_t thread_id); /* * Only call this though kpl_env_object_return */ void kpl_memory_allocator_return(kpl_memory_allocator *memory_allocator, void *object);