summaryrefslogtreecommitdiff
path: root/Source/DirectFB/lib/direct/mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/lib/direct/mem.c')
-rwxr-xr-xSource/DirectFB/lib/direct/mem.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/Source/DirectFB/lib/direct/mem.c b/Source/DirectFB/lib/direct/mem.c
new file mode 100755
index 0000000..7b65a32
--- /dev/null
+++ b/Source/DirectFB/lib/direct/mem.c
@@ -0,0 +1,350 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This 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 2 of the License, or (at your option) any later version.
+
+ This 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 this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+
+#include <direct/build.h>
+
+
+#if DIRECT_BUILD_DEBUGS /* Build with debug support? */
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <direct/debug.h>
+#include <direct/mem.h>
+#include <direct/memcpy.h>
+#include <direct/messages.h>
+#include <direct/trace.h>
+#include <direct/util.h>
+
+
+D_DEBUG_DOMAIN( Direct_Mem, "Direct/Mem", "libdirect memory allocation (debugging)" );
+
+/**********************************************************************************************************************/
+
+typedef struct {
+ const void *mem;
+ size_t bytes;
+ const char *func;
+ const char *file;
+ int line;
+ DirectTraceBuffer *trace;
+} MemDesc;
+
+/**********************************************************************************************************************/
+
+static int alloc_count = 0;
+static int alloc_capacity = 0;
+static MemDesc *alloc_list = NULL;
+static pthread_mutex_t alloc_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/**********************************************************************************************************************/
+
+void
+direct_print_memleaks( void )
+{
+ unsigned int i;
+
+ /* Debug only. */
+ pthread_mutex_lock( &alloc_lock );
+
+ if (alloc_count && (!direct_config || direct_config->debugmem)) {
+ direct_log_printf( NULL, "Local memory allocations remaining (%d): \n", alloc_count );
+
+ for (i=0; i<alloc_count; i++) {
+ MemDesc *desc = &alloc_list[i];
+
+ direct_log_printf( NULL, "%7zu bytes at %p allocated in %s (%s: %u)\n",
+ desc->bytes, desc->mem, desc->func, desc->file, desc->line );
+
+ if (desc->trace)
+ direct_trace_print_stack( desc->trace );
+ }
+ }
+
+ pthread_mutex_unlock( &alloc_lock );
+}
+
+/**********************************************************************************************************************/
+
+/* FIXME: Replace array by linked list, or at least avoid the memmove on free of an item. */
+
+static MemDesc *
+allocate_mem_desc( void )
+{
+ int cap = alloc_capacity;
+
+ if (!cap)
+ cap = 64;
+ else if (cap == alloc_count)
+ cap <<= 1;
+
+ if (cap != alloc_capacity) {
+ void *new_list = malloc( sizeof(MemDesc) * cap );
+
+ if (!new_list) {
+ D_WARN( "could not allocate more descriptors (%d->%d)", alloc_capacity, cap );
+ return NULL;
+ }
+
+ direct_memcpy( new_list, alloc_list, sizeof(MemDesc) * alloc_count );
+
+ free( alloc_list );
+
+ alloc_capacity = cap;
+ alloc_list = new_list;
+ }
+
+ return &alloc_list[alloc_count++];
+}
+
+static inline void
+fill_mem_desc( MemDesc *desc, const void *mem, int bytes,
+ const char *func, const char *file, int line, DirectTraceBuffer *trace )
+{
+ desc->mem = mem;
+ desc->bytes = bytes;
+ desc->func = func;
+ desc->file = file;
+ desc->line = line;
+ desc->trace = trace;
+}
+
+/**********************************************************************************************************************/
+
+void *
+direct_malloc( const char* file, int line, const char *func, size_t bytes )
+{
+ void *mem;
+ MemDesc *desc;
+
+ D_DEBUG_AT( Direct_Mem, " +%6zu bytes [%s:%d in %s()]\n", bytes, file, line, func );
+
+ mem = malloc( bytes );
+ if (!mem)
+ return NULL;
+
+ if (!direct_config->debugmem)
+ return mem;
+
+
+ /* Debug only. */
+ pthread_mutex_lock( &alloc_lock );
+ desc = allocate_mem_desc();
+ pthread_mutex_unlock( &alloc_lock );
+
+ if (desc)
+ fill_mem_desc( desc, mem, bytes, func, file, line, direct_trace_copy_buffer(NULL) );
+
+ return mem;
+}
+
+void *
+direct_calloc( const char* file, int line, const char *func, size_t count, size_t bytes )
+{
+ void *mem;
+ MemDesc *desc;
+
+ D_DEBUG_AT( Direct_Mem, " +%6zu bytes [%s:%d in %s()]\n", count * bytes, file, line, func );
+
+ mem = calloc( count, bytes );
+ if (!mem)
+ return NULL;
+
+ if (!direct_config->debugmem)
+ return mem;
+
+
+ /* Debug only. */
+ pthread_mutex_lock( &alloc_lock );
+ desc = allocate_mem_desc();
+ pthread_mutex_unlock( &alloc_lock );
+
+ if (desc)
+ fill_mem_desc( desc, mem, count * bytes, func, file, line, direct_trace_copy_buffer(NULL) );
+
+ return mem;
+}
+
+void *
+direct_realloc( const char *file, int line, const char *func, const char *what, void *mem, size_t bytes )
+{
+ int i;
+
+ if (!mem)
+ return direct_malloc( file, line, func, bytes );
+
+ if (!bytes) {
+ direct_free( file, line, func, what, mem );
+ return NULL;
+ }
+
+ if (!direct_config->debugmem) {
+ D_DEBUG_AT( Direct_Mem, " *%6zu bytes [%s:%d in %s()] '%s'\n", bytes, file, line, func, what );
+ return realloc( mem, bytes );
+ }
+
+
+ /* Debug only. */
+ pthread_mutex_lock( &alloc_lock );
+
+ for (i=0; i<alloc_count; i++) {
+ MemDesc *desc = &alloc_list[i];
+
+ if (desc->mem == mem) {
+ void *new_mem = realloc( mem, bytes );
+
+ D_DEBUG_AT( Direct_Mem, " %c%6zu bytes [%s:%d in %s()] (%s%zu) <- %p -> %p '%s'\n",
+ (bytes > desc->bytes) ? '>' : '<', bytes, file, line, func,
+ (bytes > desc->bytes) ? "+" : "", bytes - desc->bytes, mem, new_mem, what);
+
+ if (desc->trace) {
+ direct_trace_free_buffer( desc->trace );
+ desc->trace = NULL;
+ }
+
+ if (!new_mem) {
+ D_WARN( "could not reallocate memory (%p: %zu->%zu)", mem, desc->bytes, bytes );
+
+ alloc_count--;
+
+ /* FIXME: This can be very slow. */
+ if (i < alloc_count)
+ direct_memmove( desc, desc + 1, (alloc_count - i) * sizeof(MemDesc) );
+ }
+ else
+ fill_mem_desc( desc, new_mem, bytes, func, file, line, direct_trace_copy_buffer(NULL) );
+
+ pthread_mutex_unlock( &alloc_lock );
+
+ return new_mem;
+ }
+ }
+
+ pthread_mutex_unlock( &alloc_lock );
+
+ D_ERROR( "Direct/Mem: Not reallocating unknown %p (%s) from [%s:%d in %s()] - corrupt/incomplete list?\n",
+ mem, what, file, line, func );
+
+ return direct_malloc( file, line, func, bytes );
+}
+
+void
+direct_free( const char *file, int line, const char *func, const char *what, void *mem )
+{
+ unsigned int i;
+
+ if (!mem) {
+ D_WARN( "%s (NULL) called", __FUNCTION__ );
+ return;
+ }
+
+ if (!direct_config->debugmem) {
+ D_DEBUG_AT( Direct_Mem, " - number of bytes of %s [%s:%d in %s()] -> %p\n", what, file, line, func, mem );
+ free( mem );
+ return;
+ }
+
+
+ /* Debug only. */
+ pthread_mutex_lock( &alloc_lock );
+
+ for (i=0; i<alloc_count; i++) {
+ MemDesc *desc = &alloc_list[i];
+
+ if (desc->mem == mem) {
+ free( mem );
+
+ D_DEBUG_AT( Direct_Mem, " -%6zu bytes [%s:%d in %s()] -> %p '%s'\n",
+ desc->bytes, file, line, func, mem, what );
+
+ if (desc->trace)
+ direct_trace_free_buffer( desc->trace );
+
+ alloc_count--;
+
+ /* FIXME: This can be very slow. */
+ if (i < alloc_count)
+ direct_memmove( desc, desc + 1, (alloc_count - i) * sizeof(MemDesc) );
+
+ pthread_mutex_unlock( &alloc_lock );
+
+ return;
+ }
+ }
+
+ pthread_mutex_unlock( &alloc_lock );
+
+ D_ERROR( "Direct/Mem: Not freeing unknown %p (%s) from [%s:%d in %s()] - corrupt/incomplete list?\n",
+ mem, what, file, line, func );
+}
+
+char *
+direct_strdup( const char* file, int line, const char *func, const char *string )
+{
+ void *mem;
+ MemDesc *desc;
+ size_t length = strlen( string ) + 1;
+
+ mem = malloc( length );
+ D_DEBUG_AT( Direct_Mem, " +%6zu bytes [%s:%d in %s()] -> %p \"%30s\"\n", length, file, line, func, mem, string );
+ if (!mem)
+ return NULL;
+
+ direct_memcpy( mem, string, length );
+
+ if (!direct_config->debugmem)
+ return mem;
+
+
+ /* Debug only. */
+ pthread_mutex_lock( &alloc_lock );
+ desc = allocate_mem_desc();
+ pthread_mutex_unlock( &alloc_lock );
+
+ if (desc)
+ fill_mem_desc( desc, mem, length, func, file, line, direct_trace_copy_buffer(NULL) );
+
+ return mem;
+}
+
+/**********************************************************************************************************************/
+
+#else
+
+void
+direct_print_memleaks( void )
+{
+}
+
+#endif
+