commit eb66eb83f13ad3e58c2094a87a6a93aaef778d33
parent a23755e7701fa360f71b7538eeaab0db404ec19d
Author: vaplv <vaplv@free.fr>
Date: Wed, 6 Sep 2017 10:57:30 +0200
Merge branch 'feature_lifo_allocator' into develop
Diffstat:
7 files changed, 671 insertions(+), 306 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -46,6 +46,8 @@ set(RSYS_FILES_SRC
library.c
logger.c
mem_allocator.c
+ mem_lifo_allocator.c
+ mem_proxy_allocator.c
quaternion.c
str.c)
diff --git a/src/big_buffer.c b/src/big_buffer.c
@@ -15,13 +15,22 @@
#define _POSIX_C_SOURCE 200112L /* ftruncate support */
-#include <unistd.h>
#include "big_buffer.h"
+#ifdef COMPILER_CL
+ #include <io.h> /* _chsize support */
+#else
+ #include <unistd.h> /* ftruncate support */
+#endif
+
res_T
truncate__(FILE* file, const size_t sz)
{
ASSERT(file);
+#ifdef OS_WINDOWS
+ return _chsize(_fileno(file), (long)sz) == 0 ? RES_OK : RES_IO_ERR;
+#else
return ftruncate(fileno(file), (off_t)sz) == 0 ? RES_OK : RES_IO_ERR;
+#endif
}
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
@@ -0,0 +1,305 @@
+/* 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 lifo_data {
+ char* top;
+ char* stack;
+ size_t remain;
+ size_t capacity;
+ struct mem_allocator* allocator;
+ struct mutex* mutex;
+};
+
+/*
+ * Stack entry memory layout:
+ * +----+-----------+-----------+------+----------+--------+-----------+
+ * |... | A: 16bits | B: 48bits | DATA | C: 15bit | D: 1bit| E: 48bits |
+ * +----+-----------+-----------+------+----------+--------+-----------+
+ * \___________Header_________/ \____________Footer___________/
+ *
+ * A: size of the header in bytes
+ * B: size of DATA in bytes
+ * C: dummy data
+ * D: define whether the entry is in used or not
+ * E: size of DATA in bytes
+ */
+
+#define LIFO_DEFAULT_ALIGNMENT 8
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void*
+lifo_alloc_aligned
+ (void* data,
+ const size_t size,
+ const size_t align,
+ const char* filename,
+ const unsigned int fileline)
+{
+ struct lifo_data* lifo = data;
+ size_t align_adjusted;
+ size_t header_size;
+ size_t footer_size;
+ size_t data_size;
+ size_t entry_size;
+ char* mem;
+ int64_t header;
+ int64_t footer;
+ ASSERT(data);
+ (void)filename, (void)fileline;
+
+ if(!IS_POW2(align) || align > 32768)
+ return NULL;
+
+ align_adjusted = align < LIFO_DEFAULT_ALIGNMENT
+ ? LIFO_DEFAULT_ALIGNMENT : align;
+
+ header_size = ALIGN_SIZE(sizeof(int64_t), align_adjusted);
+ footer_size = sizeof(int64_t);
+ data_size = ALIGN_SIZE(size, sizeof(int64_t));
+ entry_size = header_size + data_size + footer_size;
+
+ ASSERT(data_size < (((int64_t)1<<48)-1));
+ ASSERT(header_size < (1<<16)-1);
+ header = (int64_t)data_size | ((int64_t)header_size<<48);
+ footer = (int64_t)data_size | ((int64_t)1<<48);
+
+ mutex_lock(lifo->mutex);
+ { /* Critical section */
+ if(lifo->remain < entry_size) {
+ mem = NULL;
+ } else {
+ lifo->remain -= entry_size;
+ mem = lifo->top + header_size;
+ ASSERT(IS_ALIGNED(lifo->top, LIFO_DEFAULT_ALIGNMENT));
+ lifo->top += entry_size;
+ *(int64_t*)(mem - sizeof(int64_t)) = header;
+ *(int64_t*)(mem + data_size) = footer;
+ }
+ }
+ mutex_unlock(lifo->mutex);
+ return mem;
+}
+
+static void*
+lifo_alloc
+ (void* data,
+ const size_t size,
+ const char* filename,
+ const unsigned int fileline)
+{
+ return lifo_alloc_aligned
+ (data, size, LIFO_DEFAULT_ALIGNMENT, filename, fileline);
+}
+
+static void*
+lifo_calloc
+ (void* data,
+ const size_t nelmts,
+ const size_t size,
+ const char* filename,
+ const unsigned int fileline)
+{
+ size_t allocation_size = nelmts * size;
+ void* mem = lifo_alloc(data, allocation_size, filename, fileline);
+ if(mem) mem = memset(mem, 0, allocation_size);
+ return mem;
+}
+
+static void
+lifo_free(void* data, void* mem)
+{
+ struct lifo_data* lifo = data;
+ int64_t header;
+ int64_t footer;
+ size_t data_size;
+ int64_t* pfooter;
+ char* ptr;
+ char* end;
+ ASSERT(data);
+
+ if(!mem) return;
+
+ ptr = mem;
+ header = *(int64_t*)(ptr-sizeof(int64_t));
+ data_size = header & (((int64_t)1<<48)-1);
+ pfooter = (int64_t*)(ptr + data_size);
+ end = ptr + data_size + sizeof(int64_t);
+
+ mutex_lock(lifo->mutex);
+ *pfooter &= ~((int64_t)1<<48); /* No more in use */
+ if(end == lifo->top) { /* Pop */
+ size_t header_size = (size_t)(header >> 48);
+ char* top = ptr - header_size;
+
+ lifo->remain += data_size + header_size + sizeof(int64_t)/*footer size*/;
+
+ while(top != lifo->stack) { /* Pop all free entries */
+ ptr = top - sizeof(int64_t);
+ footer = *(int64_t*)ptr;
+ if(footer & ((int64_t)1<<48)) break; /* In use */
+
+ data_size = footer & (((int64_t)1<<48)-1);
+ ptr -= data_size;
+
+ header = *(int64_t*)(ptr-sizeof(int64_t));
+ ASSERT(data_size == (size_t)(header & (((int64_t)1<<48)-1)));
+ header_size = (size_t)(header>>48);
+ top = ptr - header_size;
+
+ lifo->remain += data_size + header_size + sizeof(int64_t)/*footer_size*/;
+ ASSERT(lifo->remain <= lifo->capacity);
+ }
+ lifo->top = top;
+ }
+ mutex_unlock(lifo->mutex);
+}
+
+static void*
+lifo_realloc
+ (void* data,
+ void* mem,
+ const size_t size,
+ const char* filename,
+ const unsigned int fileline)
+{
+ if(size==0) {
+ lifo_free(data, mem);
+ return NULL;
+ } else {
+ size_t mem_size;
+ int64_t mem_header;
+ char* new_mem = lifo_alloc(data, size, filename, fileline);
+ if(!new_mem || !mem) return new_mem;
+ mem_header = *(int64_t*)((char*)mem - sizeof(int64_t));
+ mem_size = (size_t)(mem_header & (((int64_t)1<<48)-1));
+ memcpy(new_mem, mem, mem_size);
+ lifo_free(data, mem);
+ return new_mem;
+ }
+}
+
+static size_t
+lifo_mem_size(void* data, void* mem)
+{
+ int64_t header;
+ (void)data;
+ header = *(int64_t*)((char*)mem-sizeof(int64_t));
+ return (size_t)(header & (((int64_t)1<<48)-1));
+}
+
+static size_t
+lifo_allocated_size(const void* data)
+{
+ const struct lifo_data* lifo = data;
+ size_t size;
+ ASSERT(data);
+ mutex_lock(lifo->mutex);
+ size = lifo->capacity - lifo->remain;
+ mutex_unlock(lifo->mutex);
+ return size;
+}
+
+static size_t
+lifo_dump(const void* data, char* dump, const size_t max_dump_len)
+{
+ size_t len;
+
+ len = (size_t)snprintf
+ (dump, max_dump_len, "%lu bytes allocated.", lifo_allocated_size(data));
+ if(len >= (max_dump_len-1)) /* -1 <=> null char */
+ dump[max_dump_len-1] = '\0';
+ return len;
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+res_T
+mem_init_lifo_allocator
+ (struct mem_allocator* lifo_allocator,
+ struct mem_allocator* allocator,
+ const size_t size)
+{
+ struct lifo_data* lifo = NULL;
+ res_T res = RES_OK;
+
+ if(!allocator || !lifo_allocator) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ lifo = MEM_CALLOC(allocator, 1, sizeof(struct lifo_data));
+ if(!lifo) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ lifo->stack = MEM_ALLOC_ALIGNED(allocator, size, LIFO_DEFAULT_ALIGNMENT);
+ if(!lifo->stack) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ lifo->mutex = mutex_create();
+ if(!lifo->mutex) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ lifo->top = lifo->stack;
+ lifo->capacity = size;
+ lifo->remain = size;
+ lifo->allocator = allocator;
+
+ lifo_allocator->alloc = lifo_alloc;
+ lifo_allocator->calloc = lifo_calloc;
+ lifo_allocator->realloc = lifo_realloc;
+ lifo_allocator->mem_size = lifo_mem_size;
+ lifo_allocator->alloc_aligned = lifo_alloc_aligned;
+ lifo_allocator->rm = lifo_free;
+ lifo_allocator->allocated_size = lifo_allocated_size;
+ lifo_allocator->dump = lifo_dump;
+ lifo_allocator->data = (void*)lifo;
+
+exit:
+ return res;
+error:
+ if(lifo_allocator) {
+ mem_shutdown_lifo_allocator(lifo_allocator);
+ }
+ goto exit;
+}
+
+void
+mem_shutdown_lifo_allocator(struct mem_allocator* allocator)
+{
+ struct lifo_data* lifo;
+ ASSERT(allocator);
+ lifo = allocator->data;
+ if(lifo) {
+ if(lifo->mutex) mutex_destroy(lifo->mutex);
+ if(lifo->stack) MEM_RM(lifo->allocator, lifo->stack);
+ MEM_RM(lifo->allocator, lifo);
+ }
+ memset(allocator, 0, sizeof(struct mem_allocator));
+}
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
@@ -162,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);
@@ -172,6 +175,16 @@ main(int argc, char** argv)
mem_shutdown_proxy_allocator(&allocator2);
mem_shutdown_proxy_allocator(&allocator);
+ printf("\n-- LIFO allocator\n");
+ CHECK(mem_init_lifo_allocator(NULL, NULL, 4096), RES_BAD_ARG);
+ CHECK(mem_init_lifo_allocator(&allocator, NULL, 4096), RES_BAD_ARG);
+ CHECK(mem_init_lifo_allocator(NULL, &mem_default_allocator, 4096), RES_BAD_ARG);
+ CHECK(mem_init_lifo_allocator
+ (&allocator, &mem_default_allocator, 4096), RES_OK);
+ CHECK(MEM_ALLOC(&allocator, 4097), NULL);
+ test_allocator(&allocator);
+ mem_shutdown_lifo_allocator(&allocator);
+
CHECK(MEM_AREA_OVERLAP(mem, sizeof(int[2]), mem + 2, sizeof(int[6])), 0);
CHECK(MEM_AREA_OVERLAP(mem + 4, sizeof(int[4]), mem, sizeof(int[4])), 0);
CHECK(MEM_AREA_OVERLAP(mem, sizeof(int[2]), mem + 1, sizeof(int[7])), 1);