rsys

Basic data structures and low-level features
git clone git://git.meso-star.fr/rsys.git
Log | Files | Refs | README | LICENSE

commit 069bfc1a1a200f74ed5647057297fad0341a0a20
parent e64bc94b5ebfc5a7d4b1d0e4d83c648c5ec7c24e
Author: vaplv <vaplv@free.fr>
Date:   Wed,  6 Sep 2017 10:35:12 +0200

Refactor the Memory allocators

Move the proxy allocator implementation in a specific C file. Move the
LIFO allocator function profile into the mem_allocator.h file and remove
its own header.

Diffstat:
Mcmake/CMakeLists.txt | 2+-
Msrc/mem_allocator.c | 302------------------------------------------------------------------------------
Msrc/mem_allocator.h | 23++++++++++++++++++++---
Msrc/mem_lifo_allocator.c | 5+----
Dsrc/mem_lifo_allocator.h | 38--------------------------------------
Asrc/mem_proxy_allocator.c | 321+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_mem_allocator.c | 4+++-
7 files changed, 346 insertions(+), 349 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -47,6 +47,7 @@ set(RSYS_FILES_SRC logger.c mem_allocator.c mem_lifo_allocator.c + mem_proxy_allocator.c quaternion.c str.c) @@ -101,7 +102,6 @@ set(RSYS_FILES_INC_API logger.h math.h mem_allocator.h - mem_lifo_allocator.h mutex.h quaternion.h real2.h diff --git a/src/mem_allocator.c b/src/mem_allocator.c @@ -389,242 +389,6 @@ default_dump } /******************************************************************************* - * Proxy allocator functions - ******************************************************************************/ -#define PROXY_DEFAULT_ALIGNMENT 8 - -struct proxy_data { - struct mem_allocator* allocator; - struct mutex* mutex; - struct mem_node* node_list; -}; - -struct mem_node { - struct mem_node* next; - struct mem_node* prev; - size_t size; - const char* filename; - unsigned int fileline; - char reserved[2]; -}; - -static void* -proxy_alloc_aligned - (void* data, - const size_t size, - const size_t align, - const char* filename, - const unsigned int fileline) -{ - struct proxy_data* proxy_data = NULL; - char* mem = NULL; - size_t node_header_size = 0; - size_t node_size = 0; - size_t align_adjusted = 0; - struct mem_node* node = NULL; - - ASSERT(data); - proxy_data = data; - - if((IS_POW2(align) == 0) || align > 32768) - return NULL; - align_adjusted = align < PROXY_DEFAULT_ALIGNMENT - ? PROXY_DEFAULT_ALIGNMENT : align; - - node_header_size = ALIGN_SIZE(sizeof(struct mem_node), align_adjusted); - node_size = node_header_size + size; - node = MEM_ALLOC_ALIGNED(proxy_data->allocator, node_size, align_adjusted); - if(!node) - return NULL; - - mem = (char*)((uintptr_t)node + (uintptr_t)node_header_size); - mem[-1] = (char)(align_adjusted & 0xFF); - mem[-2] = (char)((align_adjusted >> 8) & 0xFF); - node->prev = NULL; - node->filename = filename; - node->fileline = fileline; - node->size = size; - - mutex_lock(proxy_data->mutex); - node->next = proxy_data->node_list; - if(proxy_data->node_list) - proxy_data->node_list->prev = node; - proxy_data->node_list = node; - mutex_unlock(proxy_data->mutex); - return mem; -} - -static void* -proxy_alloc - (void* data, - const size_t size, - const char* filename, - const unsigned int fileline) -{ - return proxy_alloc_aligned - (data, size, PROXY_DEFAULT_ALIGNMENT, filename, fileline); -} - -static void* -proxy_calloc - (void* data, - const size_t nbelmts, - const size_t size, - const char* filename, - const unsigned int fileline) -{ - size_t allocation_size = nbelmts * size; - void* mem = proxy_alloc_aligned - (data, allocation_size, PROXY_DEFAULT_ALIGNMENT, filename, fileline); - if(mem) - mem = memset(mem, 0, allocation_size); - return mem; -} - -static void -proxy_free(void* data, void* mem) -{ - if(mem) { - struct proxy_data* proxy_data = NULL; - struct mem_node* node = NULL; - uintptr_t alignment = 0; - - ASSERT(data); - proxy_data = data; - - alignment = (uintptr_t)(((char*)mem)[-1] | (((char*)mem)[-2] << 8)); - node = - (void*)((uintptr_t)mem - ALIGN_SIZE(sizeof(struct mem_node), alignment)); - - mutex_lock(proxy_data->mutex); - if(node->prev) { - node->prev->next = node->next; - } - if(node->next) { - node->next->prev = node->prev; - } - if(node->prev == NULL) { - proxy_data->node_list = node->next; - } - mutex_unlock(proxy_data->mutex); - MEM_RM(proxy_data->allocator, node); - } -} - -static void* -proxy_realloc - (void* data, - void* mem, - const size_t size, - const char* filename, - const unsigned int fileline) -{ - if(size == 0) { - proxy_free(data, mem); - return NULL; - } else if(mem == NULL) { - return proxy_alloc_aligned - (data, size, PROXY_DEFAULT_ALIGNMENT, filename, fileline); - } else { - struct mem_node* node = NULL; - uintptr_t node_header_size = 0; - uintptr_t alignment = 0; - - alignment = (uintptr_t)(((char*)mem)[-1] | (((char*)mem)[-2] << 8)); - node_header_size = ALIGN_SIZE(sizeof(struct mem_node), alignment); - node = (void*)((uintptr_t)mem - node_header_size); - - if(node->size == size) { - return mem; - } else { - void* dst = proxy_alloc_aligned - (data, size, alignment, filename, fileline); - if(!dst) { - proxy_free(data, mem); - return NULL; - } else { - dst = memcpy(dst, mem, size < node->size ? size : node->size); - proxy_free(data, mem); - return dst; - } - } - } -} - -static size_t -proxy_mem_size(void* data, void* mem) -{ - const uintptr_t alignment = (uintptr_t) - (((char*)mem)[-1] | (((char*)mem)[-2] << 8)); - struct mem_node* node = (struct mem_node*) - ((uintptr_t)mem - ALIGN_SIZE(sizeof(struct mem_node), alignment)); - struct proxy_data* proxy_data = (struct proxy_data*)data; - ASSERT(data); - return MEM_SIZE(proxy_data->allocator, node); -} - -static size_t -proxy_allocated_size(const void* data) -{ - const struct proxy_data* proxy_data = NULL; - struct mem_node* node = NULL; - size_t allocated_size = 0; - - ASSERT(data); - proxy_data = data; - mutex_lock(proxy_data->mutex); - for(node = proxy_data->node_list; node != NULL; node = node->next) { - allocated_size += MEM_SIZE(proxy_data->allocator, node); - } - mutex_unlock(proxy_data->mutex); - return allocated_size; -} - -static size_t -proxy_dump - (const void* data, - char* dump, - const size_t max_dump_len) -{ - const struct proxy_data* proxy_data = NULL; - struct mem_node* node = NULL; - size_t dump_len = 0; - size_t avaible_dump_space = max_dump_len ? max_dump_len - 1 /*NULL char*/ : 0; - - ASSERT(data && (!max_dump_len || dump)); - proxy_data = data; - - mutex_lock(proxy_data->mutex); - for(node = proxy_data->node_list; node != NULL; node = node->next) { - if(dump) { - const int len = snprintf - (dump, - avaible_dump_space, - "%lu bytes allocated at %s:%u%s", - (long unsigned)MEM_SIZE(proxy_data->allocator, node), - node->filename ? node->filename : "none", - node->fileline, - node->next ? ".\n" : "."); - ASSERT(len >= 0); - dump_len += (size_t)len; - - if((size_t)len < avaible_dump_space) { - dump += len; - avaible_dump_space -= (size_t)len; - } else if(dump) { - dump[avaible_dump_space] = '\0'; - avaible_dump_space = 0; - dump = NULL; - } - } - } - mutex_unlock(proxy_data->mutex); - return dump_len; -} - -#undef PROXY_DEFAULT_ALIGNMENT - -/******************************************************************************* * Default allocator ******************************************************************************/ static struct alloc_counter default_alloc_counter = {0, 0}; @@ -642,72 +406,6 @@ struct mem_allocator mem_default_allocator = { }; /******************************************************************************* - * Proxy allocator - ******************************************************************************/ -res_T -mem_init_proxy_allocator - (struct mem_allocator* proxy_allocator, - struct mem_allocator* allocator) -{ - struct proxy_data* proxy_data = NULL; - res_T res = RES_OK; - - if(!allocator || !proxy_allocator) { - res = RES_BAD_ARG; - goto error; - } - - proxy_data = MEM_CALLOC(allocator, 1, sizeof(struct proxy_data)); - if(!proxy_data) { - res = RES_MEM_ERR; - goto error; - } - proxy_data->mutex = mutex_create(); - if(!proxy_data->mutex) { - res = RES_MEM_ERR; - goto error; - } - proxy_data->allocator = allocator; - proxy_data->node_list = NULL; - - proxy_allocator->alloc = proxy_alloc; - proxy_allocator->calloc = proxy_calloc; - proxy_allocator->realloc = proxy_realloc; - proxy_allocator->mem_size = proxy_mem_size; - proxy_allocator->alloc_aligned = proxy_alloc_aligned; - proxy_allocator->rm = proxy_free; - proxy_allocator->allocated_size = proxy_allocated_size; - proxy_allocator->dump = proxy_dump; - proxy_allocator->data = (void*)proxy_data; - -exit: - return res; -error: - if(proxy_data) { - if(proxy_data->mutex) mutex_destroy(proxy_data->mutex); - MEM_RM(allocator, proxy_data); - } - if(proxy_allocator) - memset(proxy_allocator, 0, sizeof(struct mem_allocator)); - goto exit; -} - -void -mem_shutdown_proxy_allocator(struct mem_allocator* proxy) -{ - struct proxy_data* proxy_data = NULL; - struct mem_allocator* allocator = NULL; - - ASSERT(proxy); - proxy_data = proxy->data; - ASSERT(proxy_data->node_list == NULL); - mutex_destroy(proxy_data->mutex); - allocator = proxy_data->allocator; - MEM_RM(allocator, proxy_data); - memset(proxy, 0, sizeof(struct mem_allocator)); -} - -/******************************************************************************* * Regular allocator ******************************************************************************/ res_T diff --git a/src/mem_allocator.h b/src/mem_allocator.h @@ -104,7 +104,7 @@ BEGIN_DECLS RSYS_API struct mem_allocator mem_default_allocator; /******************************************************************************* - * Regular allocation functions + * Regular allocation functions. ******************************************************************************/ RSYS_API void* mem_alloc(const size_t size); RSYS_API void* mem_calloc(const size_t nelmts, const size_t size); @@ -115,7 +115,7 @@ RSYS_API size_t mem_size(void* ptr); RSYS_API size_t mem_allocated_size(void); /******************************************************************************* - * Proxy allocator + * Proxy allocator - Register the filename and the fileline of the allocation. ******************************************************************************/ RSYS_API res_T mem_init_proxy_allocator @@ -127,7 +127,7 @@ mem_shutdown_proxy_allocator (struct mem_allocator* proxy_allocator); /******************************************************************************* - * Regular allocator + * Regular allocator - Wrap the regular allocation functions. ******************************************************************************/ RSYS_API res_T mem_init_regular_allocator @@ -137,6 +137,23 @@ RSYS_API void mem_shutdown_regular_allocator (struct mem_allocator* allocator); +/******************************************************************************* + * LIFO allocator - Allocate the memory in a preallocated memory chunk wrt to a + * LIFO pattern; the last allocated entry is the first that can be deallocated. + * If the entry to delete is not on top of the LIFO stack, it is marked as + * freed and will be effectively removed when it will be on top of the LIFO + * stack. + ******************************************************************************/ +RSYS_API res_T +mem_init_lifo_allocator + (struct mem_allocator* lifo_allocator, + struct mem_allocator* allocator, + const size_t size); /* Overall size that can be allocated by the allocator */ + +RSYS_API void +mem_shutdown_lifo_allocator + (struct mem_allocator* lifo_allocator); + END_DECLS #endif /* MEM_ALLOCATOR_H */ diff --git a/src/mem_lifo_allocator.c b/src/mem_lifo_allocator.c @@ -15,13 +15,10 @@ #define _POSIX_C_SOURCE 200112L /* snprintf support */ +#include "io_c99.h" #include "math.h" #include "mem_allocator.h" -#include "mem_lifo_allocator.h" #include "mutex.h" -#ifdef OS_WINDOWS - #include "io_c99.h" -#endif #include <string.h> struct lifo_data { diff --git a/src/mem_lifo_allocator.h b/src/mem_lifo_allocator.h @@ -1,38 +0,0 @@ -/* Copyright (C) 2013-2017 Vincent Forest (vaplv@free.fr) - * - * The RSys library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The RSys library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef MEM_LIFO_ALLOCATOR_H -#define MEM_LIFO_ALLOCATOR_H - -#include "rsys.h" - -struct mem_allocator; - -BEGIN_DECLS - -RSYS_API res_T -mem_init_lifo_allocator - (struct mem_allocator* lifo_allocator, - struct mem_allocator* allocator, - const size_t size); /* Overall size that can be allocated by the allocator */ - -RSYS_API void -mem_shutdown_lifo_allocator - (struct mem_allocator* lifo_allocator); - -END_DECLS - -#endif /* MEM_LIFO_ALLOCATOR_H */ - diff --git a/src/mem_proxy_allocator.c b/src/mem_proxy_allocator.c @@ -0,0 +1,321 @@ +/* Copyright (C) 2013-2017 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200112L /* snprintf support */ + +#include "io_c99.h" +#include "math.h" +#include "mem_allocator.h" +#include "mutex.h" + +#include <string.h> + +struct proxy_data { + struct mem_allocator* allocator; + struct mutex* mutex; + struct mem_node* node_list; +}; + +struct mem_node { + struct mem_node* next; + struct mem_node* prev; + size_t size; + const char* filename; + unsigned int fileline; + char reserved[2]; +}; + +#define PROXY_DEFAULT_ALIGNMENT 8 + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void* +proxy_alloc_aligned + (void* data, + const size_t size, + const size_t align, + const char* filename, + const unsigned int fileline) +{ + struct proxy_data* proxy_data = NULL; + char* mem = NULL; + size_t node_header_size = 0; + size_t node_size = 0; + size_t align_adjusted = 0; + struct mem_node* node = NULL; + + ASSERT(data); + proxy_data = data; + + if((IS_POW2(align) == 0) || align > 32768) + return NULL; + align_adjusted = align < PROXY_DEFAULT_ALIGNMENT + ? PROXY_DEFAULT_ALIGNMENT : align; + + node_header_size = ALIGN_SIZE(sizeof(struct mem_node), align_adjusted); + node_size = node_header_size + size; + node = MEM_ALLOC_ALIGNED(proxy_data->allocator, node_size, align_adjusted); + if(!node) + return NULL; + + mem = (char*)((uintptr_t)node + (uintptr_t)node_header_size); + mem[-1] = (char)(align_adjusted & 0xFF); + mem[-2] = (char)((align_adjusted >> 8) & 0xFF); + node->prev = NULL; + node->filename = filename; + node->fileline = fileline; + node->size = size; + + mutex_lock(proxy_data->mutex); + node->next = proxy_data->node_list; + if(proxy_data->node_list) + proxy_data->node_list->prev = node; + proxy_data->node_list = node; + mutex_unlock(proxy_data->mutex); + return mem; +} + +static void* +proxy_alloc + (void* data, + const size_t size, + const char* filename, + const unsigned int fileline) +{ + return proxy_alloc_aligned + (data, size, PROXY_DEFAULT_ALIGNMENT, filename, fileline); +} + +static void* +proxy_calloc + (void* data, + const size_t nbelmts, + const size_t size, + const char* filename, + const unsigned int fileline) +{ + size_t allocation_size = nbelmts * size; + void* mem = proxy_alloc_aligned + (data, allocation_size, PROXY_DEFAULT_ALIGNMENT, filename, fileline); + if(mem) + mem = memset(mem, 0, allocation_size); + return mem; +} + +static void +proxy_free(void* data, void* mem) +{ + if(mem) { + struct proxy_data* proxy_data = NULL; + struct mem_node* node = NULL; + uintptr_t alignment = 0; + + ASSERT(data); + proxy_data = data; + + alignment = (uintptr_t)(((char*)mem)[-1] | (((char*)mem)[-2] << 8)); + node = + (void*)((uintptr_t)mem - ALIGN_SIZE(sizeof(struct mem_node), alignment)); + + mutex_lock(proxy_data->mutex); + if(node->prev) { + node->prev->next = node->next; + } + if(node->next) { + node->next->prev = node->prev; + } + if(node->prev == NULL) { + proxy_data->node_list = node->next; + } + mutex_unlock(proxy_data->mutex); + MEM_RM(proxy_data->allocator, node); + } +} + +static void* +proxy_realloc + (void* data, + void* mem, + const size_t size, + const char* filename, + const unsigned int fileline) +{ + if(size == 0) { + proxy_free(data, mem); + return NULL; + } else if(mem == NULL) { + return proxy_alloc_aligned + (data, size, PROXY_DEFAULT_ALIGNMENT, filename, fileline); + } else { + struct mem_node* node = NULL; + uintptr_t node_header_size = 0; + uintptr_t alignment = 0; + + alignment = (uintptr_t)(((char*)mem)[-1] | (((char*)mem)[-2] << 8)); + node_header_size = ALIGN_SIZE(sizeof(struct mem_node), alignment); + node = (void*)((uintptr_t)mem - node_header_size); + + if(node->size == size) { + return mem; + } else { + void* dst = proxy_alloc_aligned + (data, size, alignment, filename, fileline); + if(!dst) { + proxy_free(data, mem); + return NULL; + } else { + dst = memcpy(dst, mem, size < node->size ? size : node->size); + proxy_free(data, mem); + return dst; + } + } + } +} + +static size_t +proxy_mem_size(void* data, void* mem) +{ + const uintptr_t alignment = (uintptr_t) + (((char*)mem)[-1] | (((char*)mem)[-2] << 8)); + struct mem_node* node = (struct mem_node*) + ((uintptr_t)mem - ALIGN_SIZE(sizeof(struct mem_node), alignment)); + struct proxy_data* proxy_data = (struct proxy_data*)data; + ASSERT(data); + return MEM_SIZE(proxy_data->allocator, node); +} + +static size_t +proxy_allocated_size(const void* data) +{ + const struct proxy_data* proxy_data = NULL; + struct mem_node* node = NULL; + size_t allocated_size = 0; + + ASSERT(data); + proxy_data = data; + mutex_lock(proxy_data->mutex); + for(node = proxy_data->node_list; node != NULL; node = node->next) { + allocated_size += MEM_SIZE(proxy_data->allocator, node); + } + mutex_unlock(proxy_data->mutex); + return allocated_size; +} + +static size_t +proxy_dump + (const void* data, + char* dump, + const size_t max_dump_len) +{ + const struct proxy_data* proxy_data = NULL; + struct mem_node* node = NULL; + size_t dump_len = 0; + size_t avaible_dump_space = max_dump_len ? max_dump_len - 1 /*NULL char*/ : 0; + + ASSERT(data && (!max_dump_len || dump)); + proxy_data = data; + + mutex_lock(proxy_data->mutex); + for(node = proxy_data->node_list; node != NULL; node = node->next) { + if(dump) { + const int len = snprintf + (dump, + avaible_dump_space, + "%lu bytes allocated at %s:%u%s", + (long unsigned)MEM_SIZE(proxy_data->allocator, node), + node->filename ? node->filename : "none", + node->fileline, + node->next ? ".\n" : "."); + ASSERT(len >= 0); + dump_len += (size_t)len; + + if((size_t)len < avaible_dump_space) { + dump += len; + avaible_dump_space -= (size_t)len; + } else if(dump) { + dump[avaible_dump_space] = '\0'; + avaible_dump_space = 0; + dump = NULL; + } + } + } + mutex_unlock(proxy_data->mutex); + return dump_len; +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ + +res_T +mem_init_proxy_allocator + (struct mem_allocator* proxy_allocator, + struct mem_allocator* allocator) +{ + struct proxy_data* proxy_data = NULL; + res_T res = RES_OK; + + if(!allocator || !proxy_allocator) { + res = RES_BAD_ARG; + goto error; + } + proxy_data = MEM_CALLOC(allocator, 1, sizeof(struct proxy_data)); + if(!proxy_data) { + res = RES_MEM_ERR; + goto error; + } + proxy_data->mutex = mutex_create(); + if(!proxy_data->mutex) { + res = RES_MEM_ERR; + goto error; + } + proxy_data->allocator = allocator; + proxy_data->node_list = NULL; + + proxy_allocator->alloc = proxy_alloc; + proxy_allocator->calloc = proxy_calloc; + proxy_allocator->realloc = proxy_realloc; + proxy_allocator->mem_size = proxy_mem_size; + proxy_allocator->alloc_aligned = proxy_alloc_aligned; + proxy_allocator->rm = proxy_free; + proxy_allocator->allocated_size = proxy_allocated_size; + proxy_allocator->dump = proxy_dump; + proxy_allocator->data = (void*)proxy_data; + +exit: + return res; +error: + if(proxy_allocator) { + mem_shutdown_proxy_allocator(proxy_allocator); + } + goto exit; +} + +void +mem_shutdown_proxy_allocator(struct mem_allocator* proxy) +{ + struct proxy_data* proxy_data = NULL; + + ASSERT(proxy); + proxy_data = proxy->data; + ASSERT(proxy_data->node_list == NULL); + if(proxy_data) { + if(proxy_data->mutex) mutex_destroy(proxy_data->mutex); + MEM_RM(proxy_data->allocator, proxy_data); + } + memset(proxy, 0, sizeof(struct mem_allocator)); +} + diff --git a/src/test_mem_allocator.c b/src/test_mem_allocator.c @@ -14,7 +14,6 @@ * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ #include "mem_allocator.h" -#include "mem_lifo_allocator.h" #include "rsys.h" #include <stdio.h> #include <stdlib.h> @@ -163,6 +162,9 @@ main(int argc, char** argv) mem_shutdown_regular_allocator(&allocator); printf("\n-- Proxy allocator of default allocator\n"); + CHECK(mem_init_proxy_allocator(NULL, NULL), RES_BAD_ARG); + CHECK(mem_init_proxy_allocator(&allocator, NULL), RES_BAD_ARG); + CHECK(mem_init_proxy_allocator(NULL, &mem_default_allocator), RES_BAD_ARG); CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); test_allocator(&allocator);