aboutsummaryrefslogtreecommitdiffstats
path: root/Source/lib/utils/allocator.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/lib/utils/allocator.c')
-rw-r--r--Source/lib/utils/allocator.c445
1 files changed, 445 insertions, 0 deletions
diff --git a/Source/lib/utils/allocator.c b/Source/lib/utils/allocator.c
new file mode 100644
index 000000000..0ed197c62
--- /dev/null
+++ b/Source/lib/utils/allocator.c
@@ -0,0 +1,445 @@
+/**
+ * @file allocator.c
+ *
+ * @brief Implementation of allocator_t.
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program 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 General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <gmp.h>
+
+#include "allocator.h"
+
+
+#ifdef LEAK_DETECTIVE
+
+typedef union memory_hdr_t memory_hdr_t;
+
+/**
+ * @brief Header of each allocated memory area.
+ *
+ * Ideas stolen from pluto's defs.c.
+ *
+ * Used to detect memory leaks.
+ */
+union memory_hdr_t {
+ /**
+ * Informations.
+ */
+ struct {
+ /**
+ * Filename withing memory was allocated.
+ */
+ const char *filename;
+ /**
+ * Line number in given file.
+ */
+ size_t line;
+ /**
+ * Allocated memory size. Needed for reallocation.
+ */
+ size_t size_of_memory;
+ /**
+ * Link to the previous and next memory area.
+ */
+ memory_hdr_t *older, *newer;
+ } info;
+ /**
+ * Force maximal alignment ?
+ *
+ */
+ unsigned long junk;
+};
+
+typedef struct private_allocator_t private_allocator_t;
+
+/**
+ * @brief Private allocator_t object.
+ *
+ * Contains private variables of allocator_t object.
+ */
+struct private_allocator_t
+{
+ /**
+ * Public part of an allocator_t object.
+ */
+ allocator_t public;
+
+ /**
+ * Global list of allocations.
+ *
+ * Thread-save through mutex.
+ */
+ memory_hdr_t *allocations;
+
+ /**
+ * Mutex used to make sure, all functions are thread-save.
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * Number of allocations done
+ */
+ u_int32_t allocs;
+
+ /**
+ * Number of frees done
+ */
+ u_int32_t frees;
+
+ /**
+ * Allocates memory with LEAK_DETECTION and
+ * returns an empty data area filled with zeros.
+ *
+ * @param this private_allocator_t object
+ * @param bytes number of bytes to allocate
+ * @param file filename from which the memory is allocated
+ * @param line line number in specific file
+ * @param use_mutex if FALSE no mutex is used for allocation
+ * @return pointer to allocated memory area
+ */
+ void * (*allocate_special) (private_allocator_t *this,size_t bytes, char * file,int line, bool use_mutex);
+};
+
+/**
+ * Implementation of private_allocator_t.allocate_special.
+ */
+static void *allocate_special(private_allocator_t *this,size_t bytes, char * file,int line, bool use_mutex)
+{
+ memory_hdr_t *allocated_memory = malloc(sizeof(memory_hdr_t) + bytes);
+
+ this->allocs++;
+
+ if (allocated_memory == NULL)
+ {
+ /* TODO LOG this case */
+ exit(-1);
+ }
+
+ if (use_mutex)
+ {
+ pthread_mutex_lock( &(this->mutex));
+ }
+
+ allocated_memory->info.line = line;
+ allocated_memory->info.filename = file;
+ allocated_memory->info.size_of_memory = bytes;
+ allocated_memory->info.older = this->allocations;
+ if (this->allocations != NULL)
+ {
+ this->allocations->info.newer = allocated_memory;
+ }
+ this->allocations = allocated_memory;
+ allocated_memory->info.newer = NULL;
+
+ /* fill memory with zero's */
+ memset(allocated_memory+1, '\0', bytes);
+ if (use_mutex)
+ {
+ pthread_mutex_unlock(&(this->mutex));
+ }
+
+ /* real memory starts after header */
+ return (allocated_memory+1);
+}
+
+/**
+ * Implementation of allocator_t.allocate.
+ */
+static void * allocate(allocator_t *allocator,size_t bytes, char * file,int line)
+{
+ private_allocator_t *this = (private_allocator_t *) allocator;
+ return (this->allocate_special(this,bytes, file,line,TRUE));
+}
+
+/**
+ * Implementation of allocator_t.allocate_as_chunk.
+ */
+static chunk_t allocate_as_chunk(allocator_t *allocator,size_t bytes, char * file,int line)
+{
+ private_allocator_t *this = (private_allocator_t *) allocator;
+ chunk_t new_chunk;
+ new_chunk.ptr = this->allocate_special(this,bytes, file,line,TRUE);
+ new_chunk.len = (new_chunk.ptr == NULL) ? 0 : bytes;
+ return new_chunk;
+}
+
+/**
+ * Implementation of allocator_t.free_pointer.
+ */
+static void free_pointer(allocator_t *allocator, void * pointer)
+{
+ private_allocator_t *this = (private_allocator_t *) allocator;
+ memory_hdr_t *allocated_memory;
+
+
+ if (pointer == NULL)
+ {
+ return;
+ }
+ this->frees++;
+ pthread_mutex_lock( &(this->mutex));
+ allocated_memory = ((memory_hdr_t *)pointer) - 1;
+
+ if (allocated_memory->info.older != NULL)
+ {
+ assert(allocated_memory->info.older->info.newer == allocated_memory);
+ allocated_memory->info.older->info.newer = allocated_memory->info.newer;
+ }
+ if (allocated_memory->info.newer == NULL)
+ {
+ assert(allocated_memory == this->allocations);
+ this->allocations = allocated_memory->info.older;
+ }
+ else
+ {
+ assert(allocated_memory->info.newer->info.older == allocated_memory);
+ allocated_memory->info.newer->info.older = allocated_memory->info.older;
+ }
+ pthread_mutex_unlock(&(this->mutex));
+ free(allocated_memory);
+}
+
+/**
+ * Implementation of allocator_t.reallocate.
+ */
+static void * reallocate(allocator_t *allocator, void * old, size_t bytes, char * file,int line)
+{
+ private_allocator_t *this = (private_allocator_t *) allocator;
+ memory_hdr_t *allocated_memory;
+
+
+ pthread_mutex_lock( &(this->mutex));
+ allocated_memory = ((memory_hdr_t *)old) - 1;
+
+ void *new_space = this->allocate_special(this,bytes,file,line,FALSE);
+
+ if (old != NULL)
+ {
+ /* the smaller size is copied to avoid overflows */
+ memcpy(new_space,old,(allocated_memory->info.size_of_memory < bytes) ? allocated_memory->info.size_of_memory : bytes);
+ }
+ pthread_mutex_unlock(&(this->mutex));
+ this->public.free_pointer(&(this->public),old);
+
+ return new_space;
+}
+
+/**
+ * Implementation of allocator_t.clone_bytes.
+ */
+static void * clone_bytes(allocator_t *allocator,void * to_clone, size_t bytes, char * file, int line)
+{
+ private_allocator_t *this = (private_allocator_t *) allocator;
+
+ if (to_clone == NULL)
+ {
+ return NULL;
+ }
+
+
+ void *new_space = this->allocate_special(this,bytes,file,line,TRUE);
+
+ if (new_space == NULL)
+ {
+ return NULL;
+ }
+
+ memcpy(new_space,to_clone,bytes);
+
+ return new_space;
+}
+
+/**
+ * Implementation of allocator_t.clone_chunk.
+ */
+static chunk_t clone_chunk(allocator_t *allocator, chunk_t chunk, char * file, int line)
+{
+ private_allocator_t *this = (private_allocator_t *) allocator;
+ chunk_t clone = CHUNK_INITIALIZER;
+
+ if (chunk.ptr && chunk.len > 0)
+ {
+ clone.ptr = this->allocate_special(this,chunk.len,file,line,TRUE);
+ clone.len = chunk.len;
+ memcpy(clone.ptr, chunk.ptr, chunk.len);
+ }
+
+ return clone;
+}
+
+/**
+ * Implementation of allocator_t.allocator_report_memory_leaks.
+ */
+static void allocator_report_memory_leaks(allocator_t *allocator)
+{
+ private_allocator_t *this = (private_allocator_t *) allocator;
+ memory_hdr_t *p = this->allocations;
+ memory_hdr_t *pprev = NULL;
+ unsigned long n = 0;
+
+ pthread_mutex_lock(&(this->mutex));
+
+ while (p != NULL)
+ {
+ assert(pprev == p->info.newer);
+ pprev = p;
+ p = p->info.older;
+ n++;
+ if (p == NULL || pprev->info.filename != p->info.filename)
+ {
+ if (n != 1)
+ fprintf(stderr,"LEAK: \"%lu * %s, line %d\"\n", n, pprev->info.filename,pprev->info.line);
+ else
+ fprintf(stderr,"LEAK: \"%s, line %d\"\n", pprev->info.filename,pprev->info.line);
+ n = 0;
+ }
+ }
+ pthread_mutex_unlock( &(this->mutex));
+ fprintf(stderr, "Allocator statistics: %d allocs, %d frees\n", this->allocs, this->frees);
+}
+
+/**
+ * Only Initiation of allocator object.
+ *
+ * All allocation macros use this object.
+ */
+static private_allocator_t allocator = {
+ public: {allocate: allocate,
+ allocate_as_chunk: allocate_as_chunk,
+ free_pointer: free_pointer,
+ reallocate: reallocate,
+ clone_bytes : clone_bytes,
+ clone_chunk : clone_chunk,
+ report_memory_leaks: allocator_report_memory_leaks},
+ allocations: NULL,
+ allocate_special : allocate_special,
+ mutex: PTHREAD_MUTEX_INITIALIZER,
+ allocs: 0,
+ frees: 0
+};
+
+
+allocator_t *global_allocator = &(allocator.public);
+
+/*
+ * Alloc function for gmp.
+ */
+void *gmp_alloc(size_t bytes)
+{
+ return allocator.allocate_special(&allocator, bytes, "[ gmp internal ]", 0 , TRUE);
+}
+
+/*
+ * Realloc function for gmp.
+ */
+void *gmp_realloc(void *old, size_t old_bytes, size_t new_bytes)
+{
+ return global_allocator->reallocate(global_allocator, old, new_bytes, "[ gmp internal ]", 0);
+}
+/*
+ * Free function for gmp.
+ */
+void gmp_free(void *ptr, size_t bytes)
+{
+ free_pointer(global_allocator, ptr);
+}
+
+/*
+ * Described in header
+ */
+void allocator_init()
+{
+ mp_set_memory_functions (gmp_alloc, gmp_realloc, gmp_free);
+}
+
+#else /* !LEAK_DETECTION */
+
+/*
+ * Described in header.
+ */
+chunk_t allocator_alloc_as_chunk(size_t bytes)
+{
+ chunk_t new_chunk;
+ new_chunk.ptr = malloc(bytes);
+ if (new_chunk.ptr == NULL)
+ {
+ exit(-1);
+ }
+ new_chunk.len = bytes;
+ return new_chunk;
+
+}
+
+/*
+ * Described in header.
+ */
+void * allocator_realloc(void * old, size_t newsize)
+{
+ void *data = realloc(old,newsize);
+ return data;
+}
+
+/*
+ * Described in header.
+ */
+void * allocator_clone_bytes(void * pointer, size_t size)
+{
+
+ void *data;
+ data = malloc(size);
+
+ if (data == NULL){exit(-1);}
+ memmove(data,pointer,size);
+
+ return (data);
+}
+
+/**
+ * Described in header.
+ */
+chunk_t allocator_clone_chunk(chunk_t chunk)
+{
+ chunk_t clone = CHUNK_INITIALIZER;
+
+ if (chunk.ptr && chunk.len > 0)
+ {
+ clone.ptr = malloc(chunk.len);
+ if (clone.ptr == NULL) {exit(-1);}
+ clone.len = chunk.len;
+ memcpy(clone.ptr, chunk.ptr, chunk.len);
+ }
+
+ return clone;
+}
+
+/*
+ * Described in header.
+ */
+void allocator_free_chunk(chunk_t *chunk)
+{
+ free(chunk->ptr);
+ chunk->ptr = NULL;
+ chunk->len = 0;
+}
+
+#endif /* LEAK_DETECTION */