[Gnucash-changes] Add functions for tracking GObject based items.

David Hampton hampton at cvs.gnucash.org
Fri Jun 10 18:07:00 EDT 2005


Log Message:
-----------
Add functions for tracking GObject based items.  To help find memory
leaks, if gnucash is compiled with --enable-ref-counts-dumps the
contents of this database will be dumped when gnucash quits.

Tags:
----
gnucash-gnome2-dev

Modified Files:
--------------
    gnucash:
        configure.in
    gnucash/src/core-utils:
        Makefile.am

Added Files:
-----------
    gnucash/src/core-utils:
        gnc-gobject-utils.c
        gnc-gobject-utils.h

Revision Data
-------------
Index: configure.in
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/configure.in,v
retrieving revision 1.359.2.51
retrieving revision 1.359.2.52
diff -Lconfigure.in -Lconfigure.in -u -r1.359.2.51 -r1.359.2.52
--- configure.in
+++ configure.in
@@ -896,9 +896,14 @@
     GNOME_COMPILE_WARNINGS
 
     # Look for libgnomeui by pkg-config
-    PKG_CHECK_MODULES(GNOME, libgnomeui-2.0 >= 2.4
-			       gtk+-2.0 >= 2.4)
+    PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.4)
+    AS_SCRUB_INCLUDE(GTK_CFLAGS)
+    AC_SUBST(GTK_CFLAGS)
+    AC_SUBST(GTK_LIBS)
+
+    PKG_CHECK_MODULES(GNOME, libgnomeui-2.0 >= 2.4)
     AS_SCRUB_INCLUDE(GNOME_CFLAGS)
+
     AC_SUBST(GNOME_CFLAGS)
     AC_SUBST(GNOME_LIBS)
 
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/core-utils/Makefile.am,v
retrieving revision 1.7.4.2
retrieving revision 1.7.4.3
diff -Lsrc/core-utils/Makefile.am -Lsrc/core-utils/Makefile.am -u -r1.7.4.2 -r1.7.4.3
--- src/core-utils/Makefile.am
+++ src/core-utils/Makefile.am
@@ -4,13 +4,15 @@
 libcore_utils_la_SOURCES = \
   core-utils.c \
   gnc-gconf-utils.c \
+  gnc-gobject-utils.c \
   gnc-hooks.c
 
 libcore_utils_la_LDFLAGS = -module
 
 libcore_utils_la_LIBADD = \
   ${GLIB_LIBS} \
-  ${GCONF_LIBS}
+  ${GCONF_LIBS} \
+  ${GTK_LIBS}
 
 libgw_core_utils_la_SOURCES = \
   gw-core-utils.c
@@ -23,6 +25,7 @@
 noinst_HEADERS = \
   core-utils.h \
   gnc-gconf-utils.h \
+  gnc-gobject-utils.h \
   gnc-hooks.h \
   gw-core-utils.h
 
@@ -32,7 +35,8 @@
   ${G_WRAP_COMPILE_ARGS} \
   ${GUILE_INCS} \
   ${GLIB_CFLAGS} \
-  ${GCONF_CFLAGS}
+  ${GCONF_CFLAGS} \
+  ${GTK_CFLAGS}
 
 gwmoddir = ${GNC_GWRAP_LIBDIR}
 gwmod_DATA = gw-core-utils-spec.scm gw-core-utils.scm
--- /dev/null
+++ src/core-utils/gnc-gobject-utils.c
@@ -0,0 +1,195 @@
+/*
+ * gnc-gobject-utils.h -- utility functions for working
+ *                        with GObjects
+ * Copyright (C) 2005 David Hampton <hampton at employees.org>
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation           Voice:  +1-617-542-5942
+ * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652
+ * Boston, MA  02111-1307,  USA       gnu at gnu.org
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include "gnc-gobject-utils.h"
+
+#include <gtk/gtk.h>	// For gtk_main_quit(). Can't get this to work with
+			// a g_source attached to the main glib context.
+
+
+/************************************************************/
+/*                      Gconf Utilities                     */
+/************************************************************/
+
+
+/** Get a pointer to the hash table used by the tracking database.  If
+ *  the hash table doesn't exist, it will be created.  If gnucash was
+ *  compiled iwh --enable-ref-count-dumps, this funtion is also the
+ *  point where the gnc_gobject_tracking_dump() function is registered
+ *  to be called the GTK exits.
+ *
+ *  @internal.
+ */
+static GHashTable*
+gnc_gobject_tracking_table (void)
+{
+  static GHashTable *singleton = NULL;
+
+  if (!singleton) {
+    singleton = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+#if DEBUG_REFERENCE_COUNTING
+    gtk_quit_add (0, (GtkFunction)gnc_gobject_tracking_dump, NULL);
+#endif
+  }
+  return singleton;
+}
+
+
+/** Dump a single object from the tracking database.  This is an
+ *  auxiliary function used by the gnc_gobject_tracking_dump()
+ *  function.  This function currently only dumps the object pointer
+ *  and the reference count.  It can be extended, if necessary, via
+ *  object introspection.
+ *
+ *  @internal.
+ */
+static void
+gnc_gobject_dump_gobject (GObject *object, const gchar *name)
+{
+  //printf("Enter %s: object %p, name %s\n", __FUNCTION__, object, name);
+  g_warning("    object %p, ref count %d", object, object->ref_count);
+  //printf("Leave %s:\n", __FUNCTION__);
+}
+
+
+/** Dump a single list of objects from the tracking database.  This is
+ *  an auxiliary function used by the gnc_gobject_tracking_dump()
+ *  function.
+ *
+ *  @internal.
+ */
+static gboolean
+gnc_gobject_dump_list (const gchar *name, GList *list, gpointer user_data)
+{
+  //printf("Enter %s: name %s, list %p\n", __FUNCTION__, name, list);
+  g_warning("  %d %s", g_list_length(list), name);
+  g_list_foreach(list, (GFunc)gnc_gobject_dump_gobject, (gpointer)name);
+  //printf("Leave %s:\n", __FUNCTION__);
+  return TRUE;
+}
+
+
+/** Dump the entire object tracking database via the g_log() family of
+ *  functions.  This function is only called when gnucash exits, and
+ *  at that point all of the objects should have been removed from the
+ *  database and freed.  Any object remaining is the result of a
+ *  memory/object leakage.
+ */
+void
+gnc_gobject_tracking_dump (void)
+{
+  GHashTable *table;
+
+  //printf("Enter %s:\n", __FUNCTION__);
+  table = gnc_gobject_tracking_table();
+
+  if (g_hash_table_size(table) > 0) {
+    g_warning("The following objects remain alive:");
+    g_hash_table_foreach_remove(table, (GHRFunc)gnc_gobject_dump_list, NULL);
+  }
+  //printf("Leave %s:\n", __FUNCTION__);
+}
+
+
+/** Tell gnucash to remember this object in the database.
+ */
+void
+gnc_gobject_tracking_remember (GObject *object, GObjectClass *klass)
+{
+  GHashTable *table;
+  GList *list;
+  const gchar *name;
+
+  g_return_if_fail(G_IS_OBJECT(object));
+
+  /* Little dance here to handle startup conditions. During object
+   * initialization the object type changes as each each parent class
+   * is initialized.  The class passed to the initialization function
+   * is always the ultimate class of the object. */
+  if (klass == NULL)
+    klass = G_OBJECT_GET_CLASS(object);
+  name = g_type_name(G_TYPE_FROM_CLASS(klass));
+
+  //printf("Enter %s: object %p of type %s\n", __FUNCTION__, object, name);
+  table = gnc_gobject_tracking_table();
+  list = g_hash_table_lookup(table, name);
+
+  if (g_list_index(list, object) != -1) {
+    g_critical("Object %p is already in list of %s", object, name);
+    //printf("Leave %s: already in list\n", __FUNCTION__);
+    return;
+  }
+
+  list = g_list_append(list, object);
+  g_hash_table_insert(table, g_strdup(name), list);
+  //printf("Leave %s:\n", __FUNCTION__);
+}
+
+
+/** Tell gnucash to remember this object in the database.
+ */
+void
+gnc_gobject_tracking_forget (GObject *object)
+{
+  GHashTable *table;
+  GList *list;
+  const gchar *name;
+
+  g_return_if_fail(G_IS_OBJECT(object));
+
+  name = G_OBJECT_TYPE_NAME(object);
+  //printf("Enter %s: object %p of type %s\n", __FUNCTION__, object, name);
+  table = gnc_gobject_tracking_table();
+  list = g_hash_table_lookup(table, name);
+  if (!list) {
+    //printf("Leave %s: list for %s objects not found.\n", __FUNCTION__, name);
+    return;
+  }
+  list = g_list_remove(list, object);
+  if (list) {
+    g_hash_table_replace(table, g_strdup(name), list);
+    //printf("Leave %s: object removed.\n", __FUNCTION__);
+  } else {
+    g_hash_table_remove(table, name);
+    //printf("Leave %s: object and list removed.\n", __FUNCTION__);
+  }
+}
+
+
+/** Get a list of all known objects of a specified type.
+ */
+const GList *
+gnc_gobject_tracking_get_list (const gchar *name)
+{
+  GHashTable *table;
+  GList *list;
+
+  //printf("Enter %s: name %s\n", __FUNCTION__, name);
+  table = gnc_gobject_tracking_table();
+  list = g_hash_table_lookup(table, name);
+  //printf("Leave %s: list %p\n", __FUNCTION__, list);
+  return list;
+}
--- /dev/null
+++ src/core-utils/gnc-gobject-utils.h
@@ -0,0 +1,115 @@
+/*
+ * gnc-gobject-utils.h -- utility functions for working
+ *                        with GObjects
+ * Copyright (C) 2005 David Hampton <hampton at employees.org>
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation           Voice:  +1-617-542-5942
+ * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652
+ * Boston, MA  02111-1307,  USA       gnu at gnu.org
+ */
+
+/** @addtogroup GLib
+    @{ */
+/** @addtogroup Gobject
+    @{ */
+
+/** @file gnc-gobject-utils.h
+ *  @brief Gobject helper routines.
+ *  @author Copyright (C) 2005 David Hampton <hampton at employees.org>
+ *
+ *  The APIs in this file are designed to provide additional
+ *  functionality to GObjects, or to make it easier to use the Gobject
+ *  system from within Gnucash.
+ */
+
+#ifndef GNC_GOBJECT_UTILS_H
+#define GNC_GOBJECT_UTILS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+/** @name Gobject Tracking Functions
+ *  @{ 
+ *
+ *  This set of functions is used to maintain a "database" of objects
+ *  that are built on top of a GObject (any level of nesting).  This
+ *  database is simply a hash table of lists.  The hash table takes
+ *  the object name as its key and returns a list of all objects of
+ *  that type.  The object is then added to, deleted from, or looked
+ *  up in the list.  The database can also be queried for a list of
+ *  all objects of a specified type.  This can be used to find
+ *  pre-existing GncTreeModels, etc.  (In this case performing a
+ *  search for a specific object wouldn't help because the information
+ *  being inspected is private to the object.)
+ *
+ *  Any object added to this databasse during the execution of gnucash
+ *  should be deleted from it before completion of the program.  WHen
+ *  the program shuts down, a list of all abjects still in the
+ *  database will be dumped out to the logfile.  This should help
+ *  developers find memoty leaks in their code where an object is
+ *  lost, or is not release because it gained an extra reference at
+ *  some point during its lifetime.
+ */
+
+
+/** Tell gnucash to remember this object in the database.
+ *
+ *  @param object The object to be tracked.  This can be a fully or
+ *  partially instantiated object.
+ *
+ *  @param klass The class structure for the object.  This argument
+ *  may be NULL if a fully instantiated object is passed in as the
+ *  first argument.  If a partially instantiated object is provided
+ *  (I.E. a parent class called this function) then this argument is
+ *  required.  This is necessary because the class of the object
+ *  changes as each of the parent class is instantiated.  The class
+ *  structure, however, status constant and always reflects the fully
+ *  instantiated object.
+ */
+void gnc_gobject_tracking_remember (GObject *object, GObjectClass *klass);
+
+/** Tell gnucash to drop this object from the database.
+ *
+ *  @param object The object to be dropped.
+ */
+void gnc_gobject_tracking_forget (GObject *object);
+
+/** Get a list of all known objects of a specified type.
+ *
+ *  @param name The type name of the objects to be found.  This is the
+ *  name used when the object type was initialized.  If unknown, it
+ *  can be found by calling G_OBJECT_TYPE_NAME(object).
+ *
+ *  @return A GList of objects of the specified type.  This list is
+ *  owned by the tracking code and must not be modified by the caller.
+ */
+const GList *gnc_gobject_tracking_get_list (const gchar *name);
+
+
+/** Dump the entire object tracking database via the g_log() family of
+ *  functions.  This function is only called when gnucash exits, and
+ *  at that point all of the objects should have been removed from the
+ *  database and freed.  Any object remaining is the result of a
+ *  memory/object leakage.
+ */
+void gnc_gobject_tracking_dump (void);
+
+/** @} */
+
+
+#endif /* GNC_GOBJECT_UTILS_H */
+/** @} */
+/** @} */


More information about the gnucash-changes mailing list