g_malloc vtable patch take two



Ok, here is a new version of the patch, ready for some doofus to screw up
with. This time i removed the dmalloc support and removed the ifdefs
around the memory profiling and checking code. I also added checks so that
g_mem_set_vtable() warns and fails if any of the default allocators has
been used before the call.

This one is pretty minimal, and I hope people not into memory vtables will
not get to offended by it. I think it is as small it can get, while still
having sufficient power to do some ugly out-of-mem stuff if you really
want. Also, the code doesn't mention out-of-mem situations or callbacks,
so your typical run-of-the-mill doofus might not get the idea to use it
for such things at all.

/ Alex

Index: gmem.h
===================================================================
RCS file: /cvs/gnome/glib/gmem.h,v
retrieving revision 1.1
diff -u -r1.1 gmem.h
--- gmem.h	2000/10/12 11:52:07	1.1
+++ gmem.h	2000/10/12 14:36:06
@@ -29,12 +29,6 @@
 
 #include <gtypes.h>
 
-/* optionally feature DMALLOC memory allocation debugger
- */
-#ifdef USE_DMALLOC
-#include "dmalloc.h"
-#endif
-
 G_BEGIN_DECLS
 
 typedef struct _GAllocator      GAllocator;
@@ -45,18 +39,12 @@
  *  in order to avoid compiler warnings. (Makes the code neater).
  */
 
-#ifdef __DMALLOC_H__
-#  define g_new(type, count)		(ALLOC (type, count))
-#  define g_new0(type, count)		(CALLOC (type, count))
-#  define g_renew(type, mem, count)	(REALLOC (mem, type, count))
-#else /* __DMALLOC_H__ */
-#  define g_new(type, count)	  \
+#define g_new(type, count)	  \
       ((type *) g_malloc ((unsigned) sizeof (type) * (count)))
-#  define g_new0(type, count)	  \
+#define g_new0(type, count)	  \
       ((type *) g_malloc0 ((unsigned) sizeof (type) * (count)))
-#  define g_renew(type, mem, count)	  \
+#define g_renew(type, mem, count)	  \
       ((type *) g_realloc (mem, (unsigned) sizeof (type) * (count)))
-#endif /* __DMALLOC_H__ */
 
 #define g_mem_chunk_create(type, pre_alloc, alloc_type)	( \
   g_mem_chunk_new (#type " mem chunks (" #pre_alloc ")", \
@@ -76,25 +64,48 @@
 
 /* Memory allocation and debugging
  */
-#ifdef USE_DMALLOC
-
-#define g_malloc(size)	     ((gpointer) MALLOC (size))
-#define g_malloc0(size)	     ((gpointer) CALLOC (char, size))
-#define g_realloc(mem,size)  ((gpointer) REALLOC (mem, char, size))
-#define g_free(mem)	     FREE (mem)
-
-#else /* !USE_DMALLOC */
+typedef struct _GMemFunctions GMemFunctions;
+struct _GMemFunctions
+{
+  gpointer (*malloc)      (gulong size);
+  gpointer (*malloc0)     (gulong size);
+  gpointer (*realloc)     (gpointer mem, gulong size);
+  gpointer (*try_malloc)  (gulong size);
+  gpointer (*try_realloc) (gpointer mem, gulong size);
+  void     (*free)        (gpointer mem);
+};
+
+typedef enum
+{
+  G_MEM_PROFILE	= 1 << 0,
+  G_MEM_CHECK	= 1 << 1
+} GMemDebugFlags;
 
 gpointer g_malloc      (gulong	  size);
+gpointer g_try_malloc  (gulong	  size);
 gpointer g_malloc0     (gulong	  size);
 gpointer g_realloc     (gpointer  mem,
 			gulong	  size);
+gpointer g_try_realloc (gpointer  mem,
+			gulong	  size);
 void	 g_free	       (gpointer  mem);
 
-#endif /* !USE_DMALLOC */
+/* Set the allocator implementation for glib. Use this if you want
+ * glib to use a different malloc/free implementation. This function
+ * must be called before any g_malloc calls are made, otherwise
+ * malloc/free calls to the default and the new allocators can become
+ * mixed up.
+ */
+void g_mem_set_vtable   (const GMemFunctions *vtable);
 
-void	 g_mem_profile (void);
-void	 g_mem_check   (gpointer  mem);
+/* Enable the memory debugging facilities in glib. This function
+ * must be called only once, and before any g_malloc calls are made,
+ * otherwise malloc/free calls to the default and the debug allocators
+ * can become mixed up.
+ */
+void g_mem_debug_enable (GMemDebugFlags flags);
+void g_mem_profile      (void);
+void g_mem_check        (gpointer       mem);
 
 /* Generic allocators
  */
Index: gmem.c
===================================================================
RCS file: /cvs/gnome/glib/gmem.c,v
retrieving revision 1.23
diff -u -r1.23 gmem.c
--- gmem.c	2000/09/25 21:28:14	1.23
+++ gmem.c	2000/10/12 14:36:06
@@ -36,29 +36,24 @@
 #include <string.h>
 #include "glib.h"
 
-/* #define ENABLE_MEM_PROFILE */
-/* #define ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS */
-/* #define ENABLE_MEM_CHECK */
 #define MEM_PROFILE_TABLE_SIZE 8192
 
 /*
  * This library can check for some attempts to do illegal things to
- * memory (ENABLE_MEM_CHECK), and can do profiling
- * (ENABLE_MEM_PROFILE).  Both features are implemented by storing
- * words before the start of the memory chunk.
+ * memory, and can do profiling. Both features are implemented by
+ * storing words before the start of the memory chunk.
  *
  * The first, at offset -2*SIZEOF_LONG, is used only if
- * ENABLE_MEM_CHECK is set, and stores 0 after the memory has been
+ * mem checking is enabled, and stores 0 after the memory has been
  * allocated and 1 when it has been freed.  The second, at offset
- * -SIZEOF_LONG, is used if either flag is set and stores the size of
- * the block.
+ * -SIZEOF_LONG stores the size of  the block.
  *
- * The MEM_CHECK flag is checked when memory is realloc'd and free'd,
+ * The mem check flag is checked when memory is realloc'd and free'd,
  * and it can be explicitly checked before using a block by calling
  * g_mem_check().
  */
 
-#if defined(ENABLE_MEM_PROFILE) && defined(ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS)
+#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
 #define ENTER_MEM_CHUNK_ROUTINE() \
   g_private_set (allocating_for_mem_chunk, \
 		g_private_get (allocating_for_mem_chunk) + 1)
@@ -132,180 +127,381 @@
 					gchar    *addr);
 
 
+static gpointer g_malloc_initial  (gulong   size);
+static gpointer g_malloc0_initial (gulong   size);
+static gpointer g_realloc_initial (gpointer mem,
+				   gulong   size);
+static void     g_free_initial    (gpointer mem);
+
+static gpointer g_malloc_real     (gulong   size);
+static gpointer g_malloc0_real    (gulong   size);
+static gpointer g_realloc_real    (gpointer mem,
+				   gulong   size);
+static void     g_free_real       (gpointer mem);
+
+static gpointer g_malloc_debug    (gulong   size);
+static gpointer g_malloc0_debug   (gulong   size);
+static gpointer g_realloc_debug   (gpointer mem,
+				   gulong   size);
+static void     g_free_debug      (gpointer mem);
+
+
 /* here we can't use StaticMutexes, as they depend upon a working
  * g_malloc, the same holds true for StaticPrivate */
 static GMutex* mem_chunks_lock = NULL;
 static GRealMemChunk *mem_chunks = NULL;
+
+GMemFunctions g_mem_vtable = {
+  g_malloc_initial,	/* malloc */
+  g_malloc0_initial,	/* malloc0 */
+  g_realloc_initial,	/* realloc */
+  g_malloc_initial,	/* try_malloc */
+  g_realloc_initial,	/* try_realloc */
+  g_free_initial	/* free */
+};
 
-#ifdef ENABLE_MEM_PROFILE
+/* Data for memory profiling: */
 static GMutex* mem_profile_lock;
-static gulong allocations[MEM_PROFILE_TABLE_SIZE] = { 0 };
+static gulong *allocations = NULL;
+static gulong *total_allocations = NULL;
 static gulong allocated_mem = 0;
 static gulong freed_mem = 0;
+
+#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
 static GPrivate* allocating_for_mem_chunk = NULL;
 #define IS_IN_MEM_CHUNK_ROUTINE() \
   GPOINTER_TO_UINT (g_private_get (allocating_for_mem_chunk))
-#endif /* ENABLE_MEM_PROFILE */
+#endif
 
+static gboolean enable_mem_profile = FALSE;
+static gboolean enable_mem_check = FALSE;
 
-#ifndef USE_DMALLOC
+static gboolean malloc_used = FALSE;
 
+void
+g_mem_set_vtable (const GMemFunctions *vtable)
+{
+  if (malloc_used)
+    g_warning ("Trying to set glib memory vtable after g_malloc has been called, ignored\n");
+  else
+    g_mem_vtable = *vtable;
+}
+
+static void
+g_mem_set_default_vtable(void)
+{
+  GMemFunctions default_vtable = {
+    g_malloc_real,	/* malloc */
+    g_malloc0_real,	/* malloc0 */
+    g_realloc_real,	/* realloc */
+    g_malloc_real,	/* try_malloc */
+    g_realloc_real,	/* try_realloc */
+    g_free_real		/* free */
+  };
+  
+  g_mem_set_vtable (&default_vtable);
+}
+
+void
+g_mem_debug_enable (GMemDebugFlags flags)
+{
+
+  GMemFunctions debug_vtable = {
+    g_malloc_debug,		/* malloc */
+    g_malloc0_debug,		/* malloc0 */
+    g_realloc_debug,		/* realloc */
+    g_malloc_debug,		/* try_malloc */
+    g_realloc_debug,		/* try_realloc */
+    g_free_debug,		/* free */
+  };
+
+  if (flags)
+    g_mem_set_vtable (&debug_vtable);
+
+  enable_mem_profile = flags & G_MEM_PROFILE;
+  enable_mem_check = flags & G_MEM_CHECK;
+
+  if (enable_mem_profile)
+    {
+      /* Use calloc here instead of g_malloc0, so that the malloc
+       * profiling code doesn't show up in the profile.
+       */
+      allocations = calloc (MEM_PROFILE_TABLE_SIZE, sizeof(gulong));
+      total_allocations = calloc (MEM_PROFILE_TABLE_SIZE, sizeof(gulong));
+      
+      if (!allocations || !total_allocations)
+	enable_mem_profile = FALSE;
+    }
+}
+
 gpointer
 g_malloc (gulong size)
 {
   gpointer p;
   
+  if (size == 0)
+    return NULL;
   
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
-  gulong *t;
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
+  p = g_mem_vtable.malloc (size);
+  if (!p)
+    g_error ("could not allocate %ld bytes", size);
   
+  return p;
+}
+
+gpointer
+g_malloc0 (gulong size)
+{
+  gpointer p;
   
   if (size == 0)
     return NULL;
   
+  p = g_mem_vtable.malloc0 (size);
+
+  if (!p)
+    g_error ("could not allocate %ld bytes", size);
   
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
-  size += SIZEOF_LONG;
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
+  return p;
+}
+
+gpointer
+g_realloc (gpointer mem,
+	   gulong   size)
+{
+  gpointer p;
+  
+  if (size == 0)
+    {
+      g_free (mem);
+      return NULL;
+    }
+  
+  p = g_mem_vtable.realloc (mem, size);
+ 
+  if (!p)
+    g_error ("could not reallocate %lu bytes", (gulong) size);
   
-#ifdef ENABLE_MEM_CHECK
+  return p;
+}
+
+gpointer
+g_try_malloc (gulong size)
+{
+  if (size == 0)
+    return NULL;
+  
+  return g_mem_vtable.try_malloc (size);
+}
+
+gpointer
+g_try_realloc (gpointer mem,
+	       gulong   size)
+{
+  if (size == 0)
+    {
+      g_free (mem);
+      return NULL;
+    }
+  
+  return  g_mem_vtable.try_realloc (mem, size);
+}
+
+void
+g_free (gpointer mem)
+{
+  if (mem)
+    g_mem_vtable.free (mem);
+}
+
+static gpointer
+g_malloc_real (gulong size)
+{
+  return (gpointer) malloc (size);
+}
+
+static gpointer
+g_malloc0_real (gulong size)
+{
+  return (gpointer) calloc (size, 1);
+}
+
+static gpointer
+g_realloc_real (gpointer mem,
+		gulong   size)
+{
+  if (!mem)
+    {
+#ifdef REALLOC_0_WORKS
+      return (gpointer) realloc (NULL, size);
+#else /* !REALLOC_0_WORKS */
+      return (gpointer) malloc (size);
+#endif /* !REALLOC_0_WORKS */
+    }
+  else
+    return (gpointer) realloc (mem, size);
+}
+
+static void
+g_free_real (gpointer mem)
+{
+  free (mem);
+}
+
+static gpointer
+g_malloc_initial (gulong size)
+{
+  g_mem_set_default_vtable ();
+  malloc_used = TRUE;
+  return g_malloc (size);
+}
+
+static gpointer
+g_malloc0_initial (gulong size)
+{
+  g_mem_set_default_vtable ();
+  malloc_used = TRUE;
+  return g_malloc0 (size);
+}
+
+static gpointer
+g_realloc_initial (gpointer mem,
+		   gulong   size)
+{
+  g_mem_set_default_vtable ();
+  malloc_used = TRUE;
+  return g_realloc (mem, size);
+}
+
+static void
+g_free_initial (gpointer mem)
+{
+  g_mem_set_default_vtable ();
+  malloc_used = TRUE;
+  g_free (mem);
+}
+
+/* Memory checking and profiling versions of the allocators: */
+
+static gpointer
+g_malloc_debug (gulong size)
+{
+  gpointer p;
+  gulong *t;
+  
   size += SIZEOF_LONG;
-#endif /* ENABLE_MEM_CHECK */
   
+  if (enable_mem_check)
+    size += SIZEOF_LONG;
   
   p = (gpointer) malloc (size);
   if (!p)
-    g_error ("could not allocate %ld bytes", size);
-  
+    return NULL;
   
-#ifdef ENABLE_MEM_CHECK
-  size -= SIZEOF_LONG;
+  if (enable_mem_check) {
+    size -= SIZEOF_LONG;
   
-  t = p;
-  p = ((guchar*) p + SIZEOF_LONG);
-  *t = 0;
-#endif /* ENABLE_MEM_CHECK */
+    t = p;
+    p = ((guchar*) p + SIZEOF_LONG);
+    *t = 0;
+  }
   
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
   size -= SIZEOF_LONG;
   
   t = p;
   p = ((guchar*) p + SIZEOF_LONG);
   *t = size;
   
-#ifdef ENABLE_MEM_PROFILE
-  g_mutex_lock (mem_profile_lock);
-#  ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
-  if(!IS_IN_MEM_CHUNK_ROUTINE()) {
-#  endif
-    if (size <= MEM_PROFILE_TABLE_SIZE - 1)
-      allocations[size-1] += 1;
-    else
-      allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
-    allocated_mem += size;
-#  ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
+  if (enable_mem_profile) {
+    g_mutex_lock (mem_profile_lock);
+#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
+    if(!IS_IN_MEM_CHUNK_ROUTINE()) {
+#endif
+      if (size <= MEM_PROFILE_TABLE_SIZE - 1)
+	{
+	  total_allocations[size-1] += 1;
+	  allocations[size-1] += 1;
+	}
+      else
+	{
+	  total_allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
+	  allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
+	}
+      allocated_mem += size;
+#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
+    }
+#endif
+    g_mutex_unlock (mem_profile_lock);
   }
-#  endif
-  g_mutex_unlock (mem_profile_lock);
-#endif /* ENABLE_MEM_PROFILE */
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
-  
   
   return p;
 }
 
-gpointer
-g_malloc0 (gulong size)
+static gpointer
+g_malloc0_debug (gulong size)
 {
   gpointer p;
-  
-  
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
   gulong *t;
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
-  
-  
-  if (size == 0)
-    return NULL;
-  
   
-#if defined (ENABLE_MEM_PROFILE) || defined (ENABLE_MEM_CHECK)
   size += SIZEOF_LONG;
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
   
-#ifdef ENABLE_MEM_CHECK
-  size += SIZEOF_LONG;
-#endif /* ENABLE_MEM_CHECK */
-  
+  if (enable_mem_check)
+    size += SIZEOF_LONG;
   
   p = (gpointer) calloc (size, 1);
   if (!p)
-    g_error ("could not allocate %ld bytes", size);
-  
+    return NULL;
   
-#ifdef ENABLE_MEM_CHECK
-  size -= SIZEOF_LONG;
+  if (enable_mem_check) {
+    size -= SIZEOF_LONG;
   
-  t = p;
-  p = ((guchar*) p + SIZEOF_LONG);
-  *t = 0;
-#endif /* ENABLE_MEM_CHECK */
+    t = p;
+    p = ((guchar*) p + SIZEOF_LONG);
+    *t = 0;
+  }
   
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
   size -= SIZEOF_LONG;
   
   t = p;
   p = ((guchar*) p + SIZEOF_LONG);
   *t = size;
   
-#  ifdef ENABLE_MEM_PROFILE
-  g_mutex_lock (mem_profile_lock);
-#    ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
-  if(!IS_IN_MEM_CHUNK_ROUTINE()) {
-#    endif
-    if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
-      allocations[size-1] += 1;
-    else
-      allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
-    allocated_mem += size;
-#    ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
+  if (enable_mem_profile) {
+    g_mutex_lock (mem_profile_lock);
+#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
+    if(!IS_IN_MEM_CHUNK_ROUTINE()) {
+#endif
+      if (size <= MEM_PROFILE_TABLE_SIZE - 1)
+	{
+	  total_allocations[size-1] += 1;
+	  allocations[size-1] += 1;
+	}
+      else
+	{
+	  total_allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
+	  allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
+	}
+      allocated_mem += size;
+#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
+    }
+#endif
+    g_mutex_unlock (mem_profile_lock);
   }
-#    endif
-  g_mutex_unlock (mem_profile_lock);
-#  endif /* ENABLE_MEM_PROFILE */
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
   
-  
   return p;
 }
 
-gpointer
-g_realloc (gpointer mem,
-	   gulong   size)
+static gpointer
+g_realloc_debug (gpointer mem,
+		 gulong   size)
 {
   gpointer p;
-  
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
   gulong *t;
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
-  
-  
-  if (size == 0)
-    {
-      g_free (mem);
-    
-      return NULL;
-    }
   
-  
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
   size += SIZEOF_LONG;
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
   
-#ifdef ENABLE_MEM_CHECK
-  size += SIZEOF_LONG;
-#endif /* ENABLE_MEM_CHECK */
+  if (enable_mem_check)
+    size += SIZEOF_LONG;
   
   
   if (!mem)
@@ -318,148 +514,172 @@
     }
   else
     {
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
       t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
-#ifdef ENABLE_MEM_PROFILE
-      g_mutex_lock (mem_profile_lock);
-      freed_mem += *t;
-      g_mutex_unlock (mem_profile_lock);
-#endif /* ENABLE_MEM_PROFILE */
+      if (enable_mem_profile) {
+	g_mutex_lock (mem_profile_lock);
+	freed_mem += *t;
+	if (*t <= (MEM_PROFILE_TABLE_SIZE - 1))
+	  allocations[*t-1] -= 1;
+	else
+	  allocations[MEM_PROFILE_TABLE_SIZE - 1] -= 1;
+	g_mutex_unlock (mem_profile_lock);
+      }
       mem = t;
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
       
-#ifdef ENABLE_MEM_CHECK
-      t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
-      if (*t >= 1)
-	g_warning ("trying to realloc freed memory\n");
-      mem = t;
-#endif /* ENABLE_MEM_CHECK */
+      if (enable_mem_check) {
+	t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
+	if (*t >= 1)
+	  g_warning ("trying to realloc freed memory\n");
+	mem = t;
+      }
       
       p = (gpointer) realloc (mem, size);
     }
   
   if (!p)
-    g_error ("could not reallocate %lu bytes", (gulong) size);
+    return NULL;
   
   
-#ifdef ENABLE_MEM_CHECK
-  size -= SIZEOF_LONG;
+  if (enable_mem_check) {
+    size -= SIZEOF_LONG;
   
-  t = p;
-  p = ((guchar*) p + SIZEOF_LONG);
-  *t = 0;
-#endif /* ENABLE_MEM_CHECK */
+    t = p;
+    p = ((guchar*) p + SIZEOF_LONG);
+    *t = 0;
+  }
   
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
   size -= SIZEOF_LONG;
   
   t = p;
   p = ((guchar*) p + SIZEOF_LONG);
   *t = size;
   
-#ifdef ENABLE_MEM_PROFILE
-  g_mutex_lock (mem_profile_lock);
+  if (enable_mem_profile) {
+    g_mutex_lock (mem_profile_lock);
 #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
-  if(!IS_IN_MEM_CHUNK_ROUTINE()) {
+    if(!IS_IN_MEM_CHUNK_ROUTINE()) {
 #endif
-    if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
-      allocations[size-1] += 1;
-    else
-      allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
-    allocated_mem += size;
+      if (size <= MEM_PROFILE_TABLE_SIZE - 1)
+	{
+	  total_allocations[size-1] += 1;
+	  allocations[size-1] += 1;
+	}
+      else
+	{
+	  total_allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
+	  allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
+	}
+      allocated_mem += size;
 #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
-  }
+    }
 #endif
-  g_mutex_unlock (mem_profile_lock);
-#endif /* ENABLE_MEM_PROFILE */
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
-  
+    g_mutex_unlock (mem_profile_lock);
+  }
   
   return p;
 }
 
-void
-g_free (gpointer mem)
+static void
+g_free_debug (gpointer mem)
 {
-  if (mem)
-    {
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
-      gulong *t;
-      gulong size;
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
-      
-#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
-      t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
-      size = *t;
-#ifdef ENABLE_MEM_PROFILE     
-      g_mutex_lock (mem_profile_lock);
-      freed_mem += size;
-      g_mutex_unlock (mem_profile_lock);
-#endif /* ENABLE_MEM_PROFILE */
-      mem = t;
-#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
-      
-#ifdef ENABLE_MEM_CHECK
-      t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
-      if (*t >= 1)
-        g_warning ("freeing previously freed (%lu times) memory\n", *t);
-      *t += 1;
-      mem = t;
+  gulong *t;
+  gulong size;
       
-      memset ((guchar*) mem + 2 * SIZEOF_LONG, 0, size);
-#else /* ENABLE_MEM_CHECK */
-      free (mem);
-#endif /* ENABLE_MEM_CHECK */
-    }
+  t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
+  size = *t;
+  if (enable_mem_profile) {
+    g_mutex_lock (mem_profile_lock);
+    freed_mem += size;
+    if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
+      allocations[size-1] -= 1;
+    else
+      allocations[MEM_PROFILE_TABLE_SIZE - 1] -= 1;
+    g_mutex_unlock (mem_profile_lock);
+  }
+  mem = t;
+  
+  if (enable_mem_check) {
+    t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
+    if (*t >= 1)
+      g_warning ("freeing previously freed (%lu times) memory\n", *t);
+    *t += 1;
+    mem = t;
+    
+    memset ((guchar*) mem + 2 * SIZEOF_LONG, 0, size);
+  }
+  free (mem);
 }
 
-#endif /* ! USE_DMALLOC */
-
-
 void
 g_mem_profile (void)
 {
-#ifdef ENABLE_MEM_PROFILE
   gint i;
   gulong local_allocations[MEM_PROFILE_TABLE_SIZE];
+  gulong local_total_allocations[MEM_PROFILE_TABLE_SIZE];
   gulong local_allocated_mem;
   gulong local_freed_mem;  
 
+  if (!enable_mem_profile)
+    g_warning("mem: g_mem_profile called with memory profiling disabled\n");
+  
   g_mutex_lock (mem_profile_lock);
   for (i = 0; i < MEM_PROFILE_TABLE_SIZE; i++)
-    local_allocations[i] = allocations[i];
+    {
+      local_allocations[i] = allocations[i];
+      local_total_allocations[i] = total_allocations[i];
+    }
   local_allocated_mem = allocated_mem;
   local_freed_mem = freed_mem;
   g_mutex_unlock (mem_profile_lock);
 
   for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++)
-    if (local_allocations[i] > 0)
-      g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
-	     "%lu allocations of %d bytes", local_allocations[i], i + 1);
-  
-  if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0)
-    g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
-	   "%lu allocations of greater than %d bytes",
-	   local_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1);
+    if (local_total_allocations[i] > 0)
+      {
+	if (local_allocations [i] > 0)
+	  g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
+		 "%lu allocations of %d bytes (%ld not freed)", local_total_allocations[i], i + 1,
+		 local_allocations[i]);
+	else
+	  g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
+		 "%lu allocations of %d bytes", local_total_allocations[i], i + 1);
+      }
+	
+  if (local_total_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0)
+    {
+      if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0)
+	g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
+	       "%lu allocations of greater than %d bytes (%ld not freed)",
+	       local_total_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1,
+	       local_allocations[MEM_PROFILE_TABLE_SIZE - 1]);
+      else
+	g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
+	       "%lu allocations of greater than %d bytes",
+	       local_total_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1);
+    }
   g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated", local_allocated_mem);
   g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed", local_freed_mem);
   g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use", local_allocated_mem - local_freed_mem);
-#endif /* ENABLE_MEM_PROFILE */
 }
 
 void
 g_mem_check (gpointer mem)
 {
-#ifdef ENABLE_MEM_CHECK
   gulong *t;
   
+  if (!enable_mem_check)
+    {
+      g_warning("mem: g_mem_check called with memory checking disabled\n");
+      return;
+    }
+  
   t = (gulong*) ((guchar*) mem - SIZEOF_LONG - SIZEOF_LONG);
   
   if (*t >= 1)
     g_warning ("mem: 0x%08lx has been freed %lu times\n", (gulong) mem, *t);
-#endif /* ENABLE_MEM_CHECK */
 }
 
+
+
 GMemChunk*
 g_mem_chunk_new (gchar  *name,
 		 gint    atom_size,
@@ -1011,8 +1231,8 @@
 g_mem_init (void)
 {
   mem_chunks_lock = g_mutex_new();
-#ifdef ENABLE_MEM_PROFILE
-  mem_profile_lock = g_mutex_new();
-  allocating_for_mem_chunk = g_private_new(NULL);
+  mem_profile_lock = g_mutex_new ();
+#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
+  allocating_for_mem_chunk = g_private_new (NULL);
 #endif
 }
Index: configure.in
===================================================================
RCS file: /cvs/gnome/glib/configure.in,v
retrieving revision 1.153
diff -u -r1.153 configure.in
--- configure.in	2000/10/12 11:52:07	1.153
+++ configure.in	2000/10/12 14:36:05
@@ -101,8 +101,6 @@
 dnl declare --enable-* args and collect ac_help strings
 AC_ARG_ENABLE(debug, [  --enable-debug=[no/minimum/yes] turn on debugging [default=$debug_default]],,enable_debug=$debug_default)
 AC_ARG_ENABLE(msg-prefix, [  --enable-msg-prefix     turn on program name and PID prefixing of messages and warnings],,enable_msg_prefix=no)
-AC_ARG_ENABLE(mem_check, [  --enable-mem-check      turn on malloc/free sanity checking [default=no]],,enable_mem_check=no)
-AC_ARG_ENABLE(mem_profile, [  --enable-mem-profile    turn on malloc profiling atexit [default=no]],,enable_mem_profile=no)
 AC_ARG_ENABLE(gc_friendly, [  --enable-gc-friendly    turn on garbage collector friendliness [default=no]],,enable_gc_friendly=no)
 AC_ARG_ENABLE(ansi, [  --enable-ansi           turn on strict ansi [default=no]],
 		    , enable_ansi=no)
@@ -111,24 +109,6 @@
 
 if test "x$enable_threads" != "xyes"; then
   enable_threads=no
-fi
-
-AC_MSG_CHECKING(whether to enable memory checking)
-if test "x$enable_mem_check" = "xyes"; then
-  AC_DEFINE(ENABLE_MEM_CHECK, 1)
-  AC_SUBST(ENABLE_MEM_CHECK)
-  AC_MSG_RESULT(yes)
-else
-  AC_MSG_RESULT(no)
-fi
-
-AC_MSG_CHECKING(whether to enable memory profiling)
-if test "x$enable_mem_profile" = "xyes"; then
-  AC_DEFINE(ENABLE_MEM_PROFILE, 1)
-  AC_SUBST(ENABLE_MEM_PROFILE)
-  AC_MSG_RESULT(yes)
-else
-  AC_MSG_RESULT(no)
 fi
 
 AC_MSG_CHECKING(whether to enable garbage collector friendliness)






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]