Skip to content

Instantly share code, notes, and snippets.

@sneppy
Last active September 25, 2021 16:03
Show Gist options
  • Save sneppy/184714f0d16d17c3e6a9865185454f60 to your computer and use it in GitHub Desktop.
Save sneppy/184714f0d16d17c3e6a9865185454f60 to your computer and use it in GitHub Desktop.
Example of a memory pool implementation in C with same size blocks
int main()
{
memory_pool_create_info_t info = {
.block_size = 1024,
.block_alignment = 32,
.num_blocks = 128
};
memory_pool_t* pool = memory_pool_create(&info);
void* blocks[128] = {};
for (int i = 0; i < 128; ++i)
{
blocks[i] = memory_pool_malloc(pool);
}
for (int i = 0; i < 128; ++i)
{
memory_pool_free(pool, blocks[i]);
}
memory_pool_destroy(pool);
}
#include <stdlib.h> // posix_memalign & free
#include <string.h> // memcpy
#define BLOCK_NEXT(block, block_size) (*(void**)((char*)block + block_size))
size_t align2up(size_t n, size_t m)
{
size_t p = m - 1;
return (n + p) & ~p;
}
memory_pool_t* memory_pool_create(memory_pool_create_info_t const* info)
{
size_t block_actual_size = align2up(info->block_size + sizeof(void*), info->block_alignment);
size_t data_size = block_actual_size * info->num_blocks;
void* buffer = NULL;
// Use malloc if you don't care about alignment or not POSIX system
if (posix_memalign(&buffer, info->block_alignment, data_size + sizeof(memory_pool_t)) != 0)
{
return NULL;
}
memory_pool_t* pool = (memory_pool_t*)((char*)buffer + data_size); // Pool struct after data
pool->buffer = buffer;
pool->head = buffer;
memcpy(&pool->info, info, sizeof(pool->info));
// Init memory blocks
void* tail = pool->head;
for (int idx = 0; idx < pool->info.num_blocks - 1; ++idx)
{
tail = BLOCK_NEXT(tail, pool->info.block_size) = tail + block_actual_size;
}
BLOCK_NEXT(tail, pool->info.block_size) = NULL;
return pool;
}
void memory_pool_destroy(memory_pool_t* pool)
{
// Maybe check all pools are returned with a loop
free(pool->buffer);
}
void* memory_pool_malloc(memory_pool_t* pool)
{
if (!pool->head)
{
// Pool exhausted
return NULL;
}
void* block = pool->head;
pool->head = BLOCK_NEXT(pool->head, pool->info.block_size);
return block;
}
void memory_pool_free(memory_pool_t* pool, void* block)
{
// Check block is in buffer range
BLOCK_NEXT(block, pool->info.block_size) = pool->head;
pool->head = block;
}
#include <stddef.h> // size_t
typedef unsigned long u32;
typedef struct
{
size_t block_size;
size_t block_alignment;
u32 num_blocks;
} memory_pool_create_info_t;
typedef struct
{
void* buffer;
void* head;
memory_pool_create_info_t info;
} memory_pool_t;
memory_pool_t* memory_pool_create(memory_pool_create_info_t const*);
void memory_pool_destroy(memory_pool_t*);
void* memory_pool_malloc(memory_pool_t*);
void memory_pool_free(memory_pool_t*, void*);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment