rsys

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

commit dbdd22f1e8a0a64aa106c44291cef3c0060d125b
parent 5a9464bd4f90a87608aedbfd6da55b7facb453ed
Author: vaplv <vaplv@free.fr>
Date:   Sat, 11 Jan 2014 16:52:26 +0100

Add libc like allocation functions

Refactor the allocator to use the libc like allocation functions

Diffstat:
Msrc/mem_allocator.c | 243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/mem_allocator.h | 29+++++++++++++++++++++++------
Msrc/rsys.h | 10+++++++---
Msrc/test_mem_allocator.c | 80++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
4 files changed, 302 insertions(+), 60 deletions(-)

diff --git a/src/mem_allocator.c b/src/mem_allocator.c @@ -2,21 +2,159 @@ #include "atomic.h" #include "mem_allocator.h" #include "math.h" +#include <errno.h> #include <malloc.h> #include <string.h> #define IS_POWER_OF_2(i) ((i) > 0 && ((i) & ((i)-1)) == 0) -/******************************************************************************* - * Default allocator functions - ******************************************************************************/ -#define TRACK_DEFAULT_ALLOC /* Enable the tracking of default allocations */ - struct alloc_counter { atomic_size_T nb_allocs; atomic_size_T allocated_size; }; +/******************************************************************************* + * Common allocation functions + ******************************************************************************/ +static struct alloc_counter g_alloc_counter = { 0, 0 }; + +void* +mem_alloc(const size_t size) +{ + void* mem = NULL; + if(size) { +#if defined(COMPILER_GCC) + mem = malloc(size); +#elif defined(COMPILER_MSVC) + const size_t DEFAULT_ALIGNMENT = 16; + mem = _aligned_offset_malloc + (size + sizeof(size_t), DEFAULT_ALIGNMENT, sizeof(size_t)); + mem = ((char*)mem) + sizeof(size_t); +#endif + } + if(mem) { + ATOMIC_ADD(&g_alloc_counter.allocated_size, mem_size(mem)); + ATOMIC_INCR(&g_alloc_counter.nb_allocs); + } + return mem; +} + +void* +mem_calloc(const size_t nelmts, const size_t size) +{ + void* mem = NULL; + const size_t alloc_size = nelmts * size; + mem = mem_alloc(alloc_size); + if(mem) { + memset(mem, 0, alloc_size); + } + return mem; +} + +void* +mem_realloc(void* mem, const size_t size) +{ + void* new_mem = NULL; + + if(mem == NULL) { + new_mem = mem_alloc(size); + } else if(size == 0) { + mem_free(mem); + } else { + const size_t old_size = mem_size(mem); + + ASSERT + ( old_size < (size_t)INT64_MAX + && g_alloc_counter.allocated_size >= old_size); + ATOMIC_SUB( &g_alloc_counter.allocated_size, old_size); + +#if defined(COMPILER_MSVC) + mem = ((char*)mem) - sizeof(size_t); + new_mem = _aligned_offset_realloc + (mem, size + sizeof(size_t), ((size_t*)mem)[0], sizeof(size_t)); + new_mem = ((char*)new_mem) + sizeof(size_t); +#else + new_mem = realloc( mem, size ); +#endif + ATOMIC_ADD(&g_alloc_counter.allocated_size, mem_size(new_mem)); + } + return new_mem; + +} +void* +mem_alloc_aligned(const size_t size, const size_t alignment) +{ + void* mem = NULL; + + if(size + && IS_POWER_OF_2( alignment ) + && alignment <= 32768 /* 32 KB */) { +#if defined(COMPILER_MSVC) + mem = _aligned_offset_malloc + (size + sizeof(size_t), alignment, sizeof(size_t)); + ((size_t*)mem)[0] = alignment; + mem = ((char*)mem) + sizeof( size_t ); +#else + const int result = posix_memalign + (&mem, (alignment < sizeof(void*)) ? sizeof(void*) : alignment, size); + (void)result; /* avoid warning in Release */ + /* The following assert may not occur due to previous condition */ + ASSERT(result != EINVAL); + ASSERT((result != ENOMEM) || (mem == NULL)); +#endif + if(mem) { + ATOMIC_ADD(&g_alloc_counter.allocated_size, mem_size(mem)); + ATOMIC_INCR(&g_alloc_counter.nb_allocs); + } + } + return mem; +} + +void +mem_free(void* mem) +{ + if(mem) { + ASSERT + ( g_alloc_counter.nb_allocs != 0 + && mem_size(mem) < SIZE_MAX + && g_alloc_counter.allocated_size >= mem_size(mem)); + ATOMIC_SUB(&g_alloc_counter.allocated_size, mem_size(mem)); + ATOMIC_DECR(&g_alloc_counter.nb_allocs); +#if defined(COMPILER_MSVC) + mem = ((char*)mem) - sizeof(size_t); + _aligned_free( mem ); +#else + free( mem ); +#endif + } +} + +size_t +mem_size(void* mem) +{ + size_t mem_size = 0; + if(mem) { +#if defined(COMPILER_MSVC) + void* raw_mem = ((char*)mem) - sizeof(size_t); + mem_size = _aligned_msize(raw_mem, ((size_t*)raw_mem)[0], sizeof(size_t)); +#else + mem_size = malloc_usable_size(mem); +#endif + } + return mem_size; +} + +size_t +mem_allocated_size(void) +{ + return (size_t)g_alloc_counter.allocated_size; +} + +/******************************************************************************* + * Default allocator functions + ******************************************************************************/ +#define TRACK_DEFAULT_ALLOC /* Enable the tracking of default allocations */ + static void* default_alloc (void* data, @@ -30,18 +168,18 @@ default_alloc (void)fileline; if(size) { - mem = malloc(size); - #ifndef TRACK_DEFAULT_ALLOC + mem = mem_alloc(size); +#ifndef TRACK_DEFAULT_ALLOC (void)data; - #else +#else ASSERT(data); if(mem) { struct alloc_counter* counter = data; - const size_t size_mem = malloc_usable_size(mem); + const size_t size_mem = mem_size(mem); ATOMIC_ADD(&counter->allocated_size, size_mem); ATOMIC_INCR(&counter->nb_allocs); } - #endif /* TRACK_DEFAULT_ALLOC */ +#endif /* TRACK_DEFAULT_ALLOC */ } return mem; } @@ -50,11 +188,11 @@ static void default_free(void* data, void* mem) { if(mem) { - #ifndef TRACK_DEFAULT_ALLOC +#ifndef TRACK_DEFAULT_ALLOC (void)data; - #else +#else struct alloc_counter* counter = data; - size_t size_mem = malloc_usable_size(mem); + size_t size_mem = mem_size(mem); ASSERT ( (data != NULL) & (counter->nb_allocs != 0) @@ -62,8 +200,8 @@ default_free(void* data, void* mem) ATOMIC_SUB(&counter->allocated_size, size_mem); ATOMIC_DECR(&counter->nb_allocs); - #endif /* TRACK_DEFAULT_ALLOC */ - free(mem); +#endif /* TRACK_DEFAULT_ALLOC */ + mem_free(mem); } } @@ -95,12 +233,12 @@ default_realloc { void* new_mem = NULL; - #ifndef TRACK_DEFAULT_ALLOC +#ifndef TRACK_DEFAULT_ALLOC (void)data; (void)filename; (void)fileline; - new_mem = realloc(mem, size); - #else + new_mem = mem_realloc(mem, size); +#else ASSERT(data); if(!mem) { new_mem = default_alloc(data, size, filename, fileline); @@ -109,23 +247,23 @@ default_realloc default_free(data, mem); } else { struct alloc_counter* counter = data; - const size_t size_old = malloc_usable_size(mem); + const size_t size_old = mem_size(mem); size_t size_new = 0; ASSERT(counter->allocated_size >= size_old); ATOMIC_SUB(&counter->allocated_size, size_old); - new_mem = realloc(mem, size); - size_new = malloc_usable_size(new_mem); + new_mem = mem_realloc(mem, size); + size_new = mem_size(new_mem); ATOMIC_ADD(&counter->allocated_size, size_new); } } - #endif /* TRACK_DEFAULT_ALLOC */ +#endif /* TRACK_DEFAULT_ALLOC */ return new_mem; } static void* -default_aligned_alloc +default_alloc_aligned (void* data, const size_t size, const size_t alignment, @@ -138,33 +276,40 @@ default_aligned_alloc (void)fileline; if(size && IS_POWER_OF_2(alignment)) { - mem = memalign(alignment, size); - #ifndef TRACK_DEFAULT_ALLOC + mem = mem_alloc_aligned(size, alignment); +#ifndef TRACK_DEFAULT_ALLOC (void)data; #else ASSERT(data); if(mem) { struct alloc_counter* counter = data; - const size_t size_mem = malloc_usable_size(mem); + const size_t size_mem = mem_size(mem); ATOMIC_ADD(&counter->allocated_size, size_mem); ATOMIC_INCR(&counter->nb_allocs); } - #endif /* TRACK_DEFAULT_ALLOC */ +#endif /* TRACK_DEFAULT_ALLOC */ } return mem; } static size_t +default_mem_size(void* data, void* mem) +{ + (void)data; + return mem_size(mem); +} + +static size_t default_allocated_size(const void* data) { - #ifndef TRACK_DEFAULT_ALLOC +#ifndef TRACK_DEFAULT_ALLOC (void)data; return 0; - #else +#else const struct alloc_counter* counter = data; ASSERT(counter != NULL); return counter->allocated_size; - #endif /* TRACK_DEFAULT_ALLOC */ +#endif /* TRACK_DEFAULT_ALLOC */ } static size_t @@ -173,13 +318,13 @@ default_dump char* dump, const size_t max_dump_len) { - #ifndef TRACK_DEFAULT_ALLOC +#ifndef TRACK_DEFAULT_ALLOC (void)data; if(dump && max_dump_len) dump[0] = '\0'; return 0; - #else +#else const struct alloc_counter* counter = data; size_t dump_len = 0; int len = 0; @@ -199,7 +344,7 @@ default_dump dump[max_dump_len-1] = '\0'; return dump_len; - #endif +#endif } /******************************************************************************* @@ -223,7 +368,7 @@ struct mem_node { }; static void* -proxy_aligned_alloc +proxy_alloc_aligned (void* data, const size_t size, const size_t align, @@ -242,12 +387,12 @@ proxy_aligned_alloc if((IS_POWER_OF_2(align) == 0) || align > 32768) return NULL; - align_adjusted = align < PROXY_DEFAULT_ALIGNMENT + 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_ALIGNED_ALLOC(proxy_data->allocator, node_size, align_adjusted); + node = MEM_ALLOC_ALIGNED(proxy_data->allocator, node_size, align_adjusted); if(!node) return NULL; @@ -272,7 +417,7 @@ proxy_alloc const char* filename, const unsigned int fileline) { - return proxy_aligned_alloc + return proxy_alloc_aligned (data, size, PROXY_DEFAULT_ALIGNMENT, filename, fileline); } @@ -285,7 +430,7 @@ proxy_calloc const unsigned int fileline) { size_t allocation_size = nbelmts * size; - void* mem = proxy_aligned_alloc + void* mem = proxy_alloc_aligned (data, allocation_size, PROXY_DEFAULT_ALIGNMENT, filename, fileline); if(mem) mem = memset(mem, 0, allocation_size); @@ -332,7 +477,7 @@ proxy_realloc proxy_free(data, mem); return NULL; } else if(mem == NULL) { - return proxy_aligned_alloc + return proxy_alloc_aligned (data, size, PROXY_DEFAULT_ALIGNMENT, filename, fileline); } else { struct mem_node* node = NULL; @@ -346,7 +491,7 @@ proxy_realloc if(node->size == size) { return mem; } else { - void* dst = proxy_aligned_alloc + void* dst = proxy_alloc_aligned (data, size, alignment, filename, fileline); if(!dst) { proxy_free(data, mem); @@ -361,6 +506,18 @@ proxy_realloc } 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; @@ -427,8 +584,9 @@ EXPORT_SYM struct mem_allocator mem_default_allocator = { default_alloc, default_calloc, default_realloc, - default_aligned_alloc, + default_alloc_aligned, default_free, + default_mem_size, default_allocated_size, default_dump, (void*)&default_alloc_counter @@ -458,7 +616,8 @@ mem_init_proxy_allocator proxy_allocator->alloc = proxy_alloc; proxy_allocator->calloc = proxy_calloc; proxy_allocator->realloc = proxy_realloc; - proxy_allocator->aligned_alloc = proxy_aligned_alloc; + proxy_allocator->mem_size = proxy_mem_size; + proxy_allocator->alloc_aligned = proxy_alloc_aligned; proxy_allocator->free = proxy_free; proxy_allocator->allocated_size = proxy_allocated_size; proxy_allocator->dump = proxy_dump; diff --git a/src/mem_allocator.h b/src/mem_allocator.h @@ -28,7 +28,7 @@ struct mem_allocator { const char* filename, const unsigned int fileline); - void* (*aligned_alloc) + void* (*alloc_aligned) (void* data, const size_t size, const size_t alignment, @@ -39,6 +39,10 @@ struct mem_allocator { (void* data, void* mem); + size_t (*mem_size) + (void* data, + void* mem); + size_t (*allocated_size) (const void* data); @@ -65,13 +69,16 @@ extern struct mem_allocator mem_default_allocator; #define MEM_REALLOC(Allocator, Mem, Size) \ ((Allocator)->realloc((Allocator)->data, (Mem), (Size), __FILE__, __LINE__)) -#define MEM_ALIGNED_ALLOC(Allocator, Size, Alignment) \ - ((Allocator)->aligned_alloc \ +#define MEM_ALLOC_ALIGNED(Allocator, Size, Alignment) \ + ((Allocator)->alloc_aligned \ ((Allocator)->data, (Size), (Alignment), __FILE__, __LINE__)) #define MEM_FREE(Allocator, Mem) \ ((Allocator)->free((Allocator)->data, (Mem))) +#define MEM_SIZE(Allocator, Mem) \ + ((Allocator)->mem_size((Allocator)->data, (Mem))) + #define MEM_ALLOCATED_SIZE(Allocator) \ ((Allocator)->allocated_size((Allocator)->data)) @@ -87,13 +94,23 @@ extern struct mem_allocator mem_default_allocator; && NULL != (Allocator)->allocated_size \ && NULL != (Allocator)->dump) -/******************************************************************************* - * Proxy allocator - ******************************************************************************/ #ifdef __cplusplus extern "C" { #endif +/******************************************************************************* + * 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); +RSYS_API void* mem_realloc(void* ptr, const size_t size); +RSYS_API void* mem_alloc_aligned(const size_t size, const size_t alignment); +RSYS_API void mem_free(void* ptr); +RSYS_API size_t mem_size(void* ptr); +RSYS_API size_t mem_allocated_size(void); +/******************************************************************************* + * Proxy allocator + ******************************************************************************/ RSYS_API void mem_init_proxy_allocator (const char* proxy_name, diff --git a/src/rsys.h b/src/rsys.h @@ -19,16 +19,20 @@ * Platform ******************************************************************************/ #if defined(__unix__) || defined(__unix) || defined(unix) - #define PLATFORM_UNIX + #define OS_UNIX +#elif defined(_WIN32) + #define OS_WINDOWS #else - #error "Unsupported platform" + #error "Unsupported OS" #endif /******************************************************************************* * Compiler ******************************************************************************/ -#if defined( __GNUC__ ) +#if defined(__GNUC__) #define COMPILER_GCC +#elif defined(_MSC_VER) + #define COMPILER_MSVC #else #error "Unsupported compiler" #endif diff --git a/src/test_mem_allocator.c b/src/test_mem_allocator.c @@ -6,19 +6,78 @@ #include <string.h> static void -regular_test(struct mem_allocator* allocator) +test_regular(void) +{ + void* p = NULL; + void* q[3] = {NULL, NULL, NULL}; + size_t i = 0; + + p = mem_alloc_aligned(1024, ALIGNOF(char)); + NCHECK(p, NULL); + CHECK(IS_ALIGNED((uintptr_t)p, ALIGNOF(char)), 1); + mem_free( p ); + + q[0] = mem_alloc_aligned(10, 64); + q[1] = mem_alloc(58); + q[2] = mem_alloc(78); + NCHECK(q[0], NULL); + NCHECK(q[1], NULL); + NCHECK(q[2], NULL); + CHECK(IS_ALIGNED((uintptr_t )q[0], 64 ), 1); + + p = mem_calloc(1, 4); + NCHECK(p, NULL); + FOR_EACH(i, 0, 4) { + CHECK(((char*)p)[i], 0); + } + FOR_EACH(i, 0, 4) { + ((char*)p)[i] = (char)i; + } + + mem_free(q[1]); + + p = mem_realloc(p, 8); + FOR_EACH(i, 0, 4) { + CHECK(((char*)p)[i], (char)i); + } + FOR_EACH(i, 4, 8) { + ((char*)p)[i] = (char)i; + } + + mem_free(q[2]); + + p = mem_realloc(p, 5); + FOR_EACH(i, 0, 5) { + CHECK(((char*)p )[i], (char)i); + } + + mem_free(p); + + p = NULL; + p = mem_realloc(NULL, 16); + NCHECK(p, NULL); + p = mem_realloc(p, 0); + + mem_free(q[0]); + + CHECK(mem_alloc_aligned(1024, 0 ), NULL); + CHECK(mem_alloc_aligned(1024, 3 ), NULL); +} + +static void +test_allocator(struct mem_allocator* allocator) { char dump[24]; void* p = NULL; void* q[3] = {NULL, NULL, NULL}; size_t i = 0; - p = MEM_ALIGNED_ALLOC(allocator, 1024, ALIGNOF(char)); + p = MEM_ALLOC_ALIGNED(allocator, 1024, ALIGNOF(char)); NCHECK(p, NULL); CHECK(IS_ALIGNED((uintptr_t)p, ALIGNOF(char)), 1); MEM_FREE(allocator, p); - q[0] = MEM_ALIGNED_ALLOC(allocator, 10, 8); + q[0] = MEM_ALLOC_ALIGNED(allocator, 10, 8); q[1] = MEM_CALLOC(allocator, 1, 58); q[2] = MEM_ALLOC(allocator, 78); NCHECK(q[0], NULL); @@ -62,8 +121,8 @@ regular_test(struct mem_allocator* allocator) MEM_FREE(allocator, q[0]); - CHECK(MEM_ALIGNED_ALLOC(allocator, 1024, 0), NULL); - CHECK(MEM_ALIGNED_ALLOC(allocator, 1024, 3), NULL); + CHECK(MEM_ALLOC_ALIGNED(allocator, 1024, 0), NULL); + CHECK(MEM_ALLOC_ALIGNED(allocator, 1024, 3), NULL); CHECK(MEM_ALLOCATED_SIZE(allocator), 0); } @@ -75,12 +134,15 @@ main(int argc, char** argv) (void)argc; (void)argv; - printf("Default allocator:\n"); - regular_test(&mem_default_allocator); + printf("-- Common allocation functions\n"); + test_regular(); + + printf("-- Default allocator\n"); + test_allocator(&mem_default_allocator); - printf("\nProxy allocator\n"); + printf("\n-- Proxy allocator\n"); mem_init_proxy_allocator("utest", &allocator, &mem_default_allocator); - regular_test(&allocator); + test_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); CHECK(MEM_ALLOCATED_SIZE(&mem_default_allocator), 0);