From 332c114cf633f70027c28ec6bedb898d9de85e51 Mon Sep 17 00:00:00 2001 From: nodist Date: Mon, 12 Oct 2026 11:06:37 -0400 Subject: basic allocator with valgrind testing --- source/memory.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 source/memory.c (limited to 'source/memory.c') diff --git a/source/memory.c b/source/memory.c new file mode 100644 index 0000000..d7618a7 --- /dev/null +++ b/source/memory.c @@ -0,0 +1,112 @@ + +#include "kpl.h" + +void kpl_memory_allocator_init(kpl_memory_allocator *memory_allocator) { + for (int32_t slab_pow2 = KPL_MEMORY_ALLOCATOR_MIN_SIZE_POW2; + slab_pow2 <= KPL_MEMORY_ALLOCATOR_MAX_SIZE_POW2; slab_pow2++) { + kpl_memory_allocator_slab_group *slab_group = &memory_allocator->slabs[slab_pow2]; + slab_group->slab_size_pow2 = slab_pow2; + slab_group->slab_head = slab_group->slab_tail = NULL; + kpl_object_queue_init(&slab_group->object_pool); + } +} + +static void kpl_memory_allocator_slab_free(kpl_memory_allocator_slab_group *slab_group) { + kpl_memory_allocator_slab *slab_head = slab_group->slab_head; + while (slab_head) { + kpl_memory_allocator_slab *slab_tmp = slab_head; + slab_head = slab_head->slab_next; + munmap(slab_tmp->buffer, slab_tmp->buffer_size); + free(slab_tmp); + } +} + +void kpl_memory_allocator_free(kpl_memory_allocator *memory_allocator) { + for (int32_t slab_pow2 = KPL_MEMORY_ALLOCATOR_MIN_SIZE_POW2; + slab_pow2 < KPL_MEMORY_ALLOCATOR_SLAB_COUNT; slab_pow2++) { + kpl_memory_allocator_slab_group *slab_group = &memory_allocator->slabs[slab_pow2]; +#ifdef KPL_VALGRIND + kpl_object *object = NULL; + while ((object = kpl_object_queue_dequeue(&slab_group->object_pool))) + VALGRIND_FREELIKE_BLOCK(object, 0); +#endif + kpl_memory_allocator_slab_free(slab_group); + } +} + +static int32_t kpl_memory_allocator_get_size_pow2(int32_t size) { + return size > 1 ? 32 - __builtin_clz(size - 1) : 0; +} + +static const int32_t pages_per_pow2[] = { + [5] = 5, + [6] = 10, + [7] = 15, + [8] = 20, + [9] = 25, + [10] = 30, + [11] = 35, + [12] = 40, + [13] = 2, + [14] = 4, + [15] = 8, + [16] = 16, + [17] = 32, + [18] = 64, + [19] = 128, + [20] = 256, + [21] = 512, + [22] = 1024, +}; + +static kpl_memory_allocator_slab *kpl_memory_allocator_slab_init(int32_t size_pow2) { + kpl_memory_allocator_slab *slab = calloc(1, sizeof(kpl_memory_allocator_slab)); + slab->buffer_size = getpagesize() * pages_per_pow2[size_pow2]; + slab->buffer = mmap(NULL, slab->buffer_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); + return slab; +} + +static void *kpl_memory_allocator_slab_bump(kpl_memory_allocator_slab *slab, int32_t size) { + void *object = slab->buffer + slab->buffer_used; + slab->buffer_used += size; + return object; +} + +static kpl_object *kpl_memory_allocator_slab_allocate(kpl_memory_allocator_slab_group *slab_group, + int32_t thread_id) { + kpl_memory_allocator_slab *slab = slab_group->slab_tail; + int32_t size = 1 << slab_group->slab_size_pow2; + if (!slab || slab->buffer_used + size > slab->buffer_size) { + slab = kpl_memory_allocator_slab_init(slab_group->slab_size_pow2); + if (!slab_group->slab_head) + slab_group->slab_head = slab_group->slab_tail = slab; + else + slab_group->slab_tail = slab_group->slab_tail->slab_next = slab; + } + kpl_object *object = kpl_memory_allocator_slab_bump(slab, size); +#ifdef KPL_VALGRIND + VALGRIND_MALLOCLIKE_BLOCK(object, size, 0, 0); +#endif + __atomic_store_n(&object->queue_next, NULL, __ATOMIC_RELAXED); + object->object_size = size; + object->thread_id = thread_id; + return object; +} + +void *kpl_memory_allocator_allocate(kpl_memory_allocator *memory_allocator, int32_t size, int32_t thread_id) { + if (size < (1 << KPL_MEMORY_ALLOCATOR_MIN_ROUND_SIZE_POW2)) + return NULL; + int32_t size_pow2 = kpl_memory_allocator_get_size_pow2(size); + if (size_pow2 < KPL_MEMORY_ALLOCATOR_MIN_SIZE_POW2) + size_pow2 = KPL_MEMORY_ALLOCATOR_MIN_SIZE_POW2; + kpl_memory_allocator_slab_group *slab_group = &memory_allocator->slabs[size_pow2]; + kpl_object *object = kpl_object_queue_dequeue(&slab_group->object_pool); + if (!object) + object = kpl_memory_allocator_slab_allocate(slab_group, thread_id); + return object; +} + +void kpl_memory_allocator_return(kpl_memory_allocator *memory_allocator, void *object) { + int32_t size_pow2 = kpl_memory_allocator_get_size_pow2(((kpl_object*) object)->object_size); + kpl_object_queue_enqueue(&memory_allocator->slabs[size_pow2].object_pool, object); +} -- cgit v1.2.3