From 6862128151fb78f63685a8da5575783c426d64a7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Apr 2006 12:10:50 +0000 Subject: ../svn-commit.tmp --- Source/lib/utils/allocator.c | 445 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 445 insertions(+) create mode 100644 Source/lib/utils/allocator.c (limited to 'Source/lib/utils/allocator.c') 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 . + * + * 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 +#include +#include +#include +#include +#include +#include + +#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 */ -- cgit v1.2.3