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:
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);