Implemented pool allocator without testing, probably buggy.

This commit is contained in:
Eric-Paul Ickhorn 2024-01-23 18:49:20 +01:00
parent 18a0832c5e
commit 886793a950
Signed by: epickh
GPG Key ID: F5EBBE013924D95F
7 changed files with 255 additions and 17 deletions

View File

@ -24,7 +24,6 @@ struct rr_generic_pool
void * (*fn_alloc) (rr_generic_pool_s *pool);
void (*fn_free) (rr_generic_pool_s *pool, void *block);
void (*fn_destruct) (rr_generic_pool_s *pool);
usz_t (*fn_get_unit_size) (rr_generic_pool_s *pool);
void *specifics;
};
@ -35,4 +34,26 @@ struct rr_generic_arena
void *specifics;
};
void * rr_alloc(rr_generic_allocator_s *allocator, usz_t size);
void rr_free(rr_generic_allocator_s *allocator, void *allocation);
void * rr_arena_alloc(rr_generic_arena_s *arena, usz_t size);
void * rr_pool_alloc(rr_generic_pool_s *pool);
void rr_pool_free(rr_generic_pool_s *pool, void *allocation);
#ifndef __RR_AVOID_STDLIB
rr_generic_allocator_s rr_provide_stdlib_allocator();
#endif // __RR_AVOID_STDLIB
rr_generic_arena_s rr_provide_arena(rr_generic_allocator_s *allocator, usz_t len_allocation);
rr_generic_pool_s rr_provide_dynamic_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity);
rr_generic_pool_s rr_provide_static_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity);
rr_generic_arena_s rr_provide_arena_from_malloc(usz_t len_allocation);
rr_generic_pool_s rr_provide_dynamic_pool_from_malloc(usz_t item_size, usz_t capacity);
rr_generic_pool_s rr_provide_static_pool_from_malloc(usz_t item_size, usz_t capacity);
#endif // RR_GENERIC_ALLOCATOR_H

View File

@ -5,7 +5,17 @@
#include <librr/types.h>
#include <librr/alloc/generic.h>
rr_generic_arena_s rr_new_arena(usz_t capacity);
typedef struct rr_arena rr_arena_s;
struct rr_arena
{
usz_t capacity;
usz_t offset;
char *allocation;
rr_generic_allocator_s *allocator;
};
rr_generic_arena_s rr_new_arena(rr_generic_allocator_s *allocator, usz_t capacity);
void rr_destruct_arena(rr_generic_arena_s *generic_arena);
void * rr_arena_alloc(rr_generic_arena_s *generic_arena, usz_t length);

View File

@ -0,0 +1,32 @@
#ifndef RR_POOL_PROVIDER_H
#define RR_POOL_PROVIDER_H
#include <librr/types.h>
#include <librr/alloc/generic.h>
typedef struct rr_pool_unit_header rr_pool_unit_header_s;
typedef struct rr_pool rr_pool_s;
struct rr_pool_unit_header
{
rr_pool_unit_header_s *next;
};
struct rr_pool
{
usz_t capacity;
usz_t item_size;
rr_pool_unit_header_s *first_free;
void *allocation;
rr_generic_allocator_s *allocator;
};
rr_generic_pool_s rr_new_dynamic_pool(rr_generic_allocator_s *allocator, usz_t unit_size, usz_t capacity);
rr_generic_pool_s rr_new_static_pool(rr_generic_allocator_s *allocator, usz_t unit_size, usz_t capacity);
void rr_destruct_pool(rr_generic_pool_s *pool);
void * rr_pool_alloc_slot(rr_generic_pool_s *pool);
void rr_pool_free_slot(rr_generic_pool_s *pool, void *block);
#endif // RR_POOL_PROVIDER_H

View File

@ -1,25 +1,15 @@
#include <librr/alloc/arena.h>
#include <alloc/arena.h>
#include <librr/strutil.h>
#include <librr/memory.h>
#include <stdlib.h>
typedef struct rr_arena rr_arena_s;
struct rr_arena
rr_generic_arena_s rr_new_arena(rr_generic_allocator_s *allocator, usz_t capacity)
{
usz_t capacity;
usz_t offset;
char *allocation;
};
rr_generic_arena_s rr_new_arena(usz_t capacity)
{
rr_arena_s *specifics = malloc(sizeof(rr_arena_s) + capacity);
rr_arena_s *specifics = rr_alloc(allocator, sizeof(rr_arena_s) + capacity);
specifics->capacity = capacity;
specifics->offset = 0;
// The arena allocation is right after the head structure.
specifics->allocation = (void *) (specifics + sizeof(rr_arena_s));
specifics->allocator = allocator;
rr_generic_arena_s arena;
arena.fn_alloc = &rr_arena_alloc;
@ -31,7 +21,8 @@ rr_generic_arena_s rr_new_arena(usz_t capacity)
void rr_destruct_arena(rr_generic_arena_s *generic_arena)
{
free(generic_arena->specifics);
rr_arena_s *arena = generic_arena->specifics;
rr_free(arena->allocator, generic_arena->specifics);
}

View File

@ -0,0 +1,88 @@
#include <librr/alloc/generic.h>
#include <librr/memory.h>
#include <alloc/pool.h>
void rr_initialize_pool_allocation(rr_pool_s *pool)
{
usz_t slot_size = sizeof(rr_pool_unit_header_s) + pool->item_size;
slot_size = (slot_size + (32 - slot_size % 32));
usz_t slot_index = 0;
while(slot_index < pool->capacity)
{
rr_pool_unit_header_s *current_header = pool->allocation + (slot_index * slot_size);
current_header->next = current_header + slot_size;
++slot_index;
}
rr_pool_unit_header_s *last_header = pool->allocation + ((pool->capacity - 1) * slot_size);
last_header->next = NULL;
}
rr_generic_pool_s rr_new_dynamic_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity)
{
// Size of (header + item) rounded up to 32
usz_t slot_size = sizeof(rr_pool_unit_header_s) + item_size;
slot_size = (slot_size + (32 - slot_size % 32));
rr_pool_s pool;
pool.allocator = allocator;
pool.allocation = rr_alloc(allocator, slot_size * capacity);
pool.item_size = item_size;
pool.capacity = capacity;
pool.first_free = pool.allocation;
rr_initialize_pool_allocation(&pool);
rr_generic_pool_s generic_pool;
generic_pool.fn_alloc = &rr_pool_alloc_slot;
generic_pool.fn_free = &rr_pool_free_slot;
generic_pool.fn_destruct = &rr_destruct_pool;
return generic_pool;
}
rr_generic_pool_s rr_new_static_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity)
{
// Size of (header + item) rounded up to 32
usz_t slot_size = sizeof(rr_pool_unit_header_s) + item_size;
slot_size = (slot_size + (32 - slot_size % 32));
rr_pool_s pool;
pool.allocator = allocator;
pool.allocation = rr_alloc(allocator, slot_size * capacity);
pool.item_size = item_size;
pool.capacity = capacity;
pool.first_free = pool.allocation;
rr_initialize_pool_allocation(&pool);
rr_generic_pool_s generic_pool;
generic_pool.fn_alloc = &rr_pool_alloc_slot;
generic_pool.fn_free = &rr_pool_free_slot;
generic_pool.fn_destruct = &rr_destruct_pool;
return generic_pool;
}
void rr_destruct_pool(rr_generic_pool_s *generic_pool)
{
rr_pool_s *specifics = generic_pool->specifics;
rr_free(specifics->allocator, specifics->allocation);
rr_free(specifics->allocator, specifics);
}
void * rr_pool_alloc_slot(rr_generic_pool_s *generic_pool)
{
rr_pool_s *specifics = generic_pool->specifics;
rr_pool_unit_header_s *header = specifics->first_free;
specifics->first_free = header->next;
void *item = header + sizeof(rr_pool_unit_header_s);
rr_memset(item, specifics->item_size, 0x00);
return item;
}
void rr_pool_free_slot(rr_generic_pool_s *generic_pool, void *block)
{
rr_pool_s *specifics = generic_pool->specifics;
rr_pool_unit_header_s *header = block - sizeof(rr_pool_unit_header_s);
header->next = specifics->first_free;
specifics->first_free = header;
}

View File

@ -0,0 +1,66 @@
#include <librr/alloc/generic.h>
#include <alloc/pool.h>
#include <alloc/arena.h>
#ifndef __RR_BAREMETAL
#include <stdlib.h>
/// @brief An allocator for the sole purpose of preventing warnings because of an unused
/// parameter in the standard allocator proxying functions.
rr_generic_allocator_s *rr_last_used_proxy_allocator;
void * rr_proxy_malloc(rr_generic_allocator_s *allocator, usz_t num_bytes)
{
rr_last_used_proxy_allocator = allocator;
return malloc(num_bytes);
}
void rr_proxy_free(rr_generic_allocator_s *allocator, void *block)
{
rr_last_used_proxy_allocator = allocator;
free(block);
}
rr_generic_allocator_s rr_provide_stdlib_allocator()
{
rr_generic_allocator_s allocator;
allocator.fn_alloc = &rr_proxy_malloc;
allocator.fn_free = &rr_proxy_free;
allocator.specifics = NULL;
allocator.fn_destruct = NULL;
return allocator;
}
#endif // __RR_BAREMETAL
rr_generic_arena_s rr_provide_arena(rr_generic_allocator_s *allocator, usz_t len_allocation)
{
return rr_new_arena(allocator, len_allocation);
}
rr_generic_pool_s rr_provide_dynamic_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity)
{
return rr_new_dynamic_pool(allocator, item_size, capacity);
}
rr_generic_pool_s rr_provide_static_pool(rr_generic_allocator_s *allocator, usz_t item_size, usz_t capacity)
{
return rr_new_dynamic_pool(allocator, item_size, capacity);
}
rr_generic_arena_s rr_provide_arena_from_malloc(usz_t len_allocation)
{
rr_generic_allocator_s allocator = rr_provide_stdlib_allocator();
return rr_new_arena(&allocator, len_allocation);
}
rr_generic_pool_s rr_provide_dynamic_pool_from_malloc(usz_t item_size, usz_t capacity)
{
rr_generic_allocator_s allocator = rr_provide_stdlib_allocator();
return rr_new_dynamic_pool(&allocator, item_size, capacity);
}
rr_generic_pool_s rr_provide_static_pool_from_malloc(usz_t item_size, usz_t capacity)
{
rr_generic_allocator_s allocator = rr_provide_stdlib_allocator();
return rr_new_static_pool(&allocator, item_size, capacity);
}

View File

@ -0,0 +1,30 @@
#include <librr/alloc/generic.h>
void * rr_alloc(rr_generic_allocator_s *allocator, usz_t size)
{
return allocator->fn_alloc(allocator, size);
}
void rr_free(rr_generic_allocator_s *allocator, void *allocation)
{
return allocator->fn_free(allocator, allocation);
}
void * rr_arena_alloc(rr_generic_arena_s *arena, usz_t size)
{
return arena->fn_alloc(arena, size);
}
void * rr_pool_alloc(rr_generic_pool_s *pool)
{
return pool->fn_alloc(pool);
}
void rr_pool_free(rr_generic_pool_s *pool, void *allocation)
{
return pool->fn_free(pool, allocation);
}