[gnome-menus] Memory leak fixes



commit fabf5ba19d1cead5c91c3669e48f090e7a60d16f
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Mon Nov 18 18:10:57 2013 -0500

    Memory leak fixes
    
    This time, with less crashes.

 libmenu/entry-directories.c |  115 +++++++++++++++++++++++++++----------------
 libmenu/gmenu-tree.c        |    4 +-
 2 files changed, 75 insertions(+), 44 deletions(-)
---
diff --git a/libmenu/entry-directories.c b/libmenu/entry-directories.c
index ee22a55..d602b99 100644
--- a/libmenu/entry-directories.c
+++ b/libmenu/entry-directories.c
@@ -64,7 +64,10 @@ struct CachedDir
   guint have_read_entries : 1;
   guint deleted : 1;
 
-  guint references : 28;
+  guint references;
+
+  GFunc    notify;
+  gpointer notify_data;
 };
 
 struct CachedDirMonitor
@@ -79,6 +82,12 @@ static void     cached_dir_remove_reference       (CachedDir *dir);
 static void     cached_dir_free                   (CachedDir  *dir);
 static gboolean cached_dir_load_entries_recursive (CachedDir  *dir,
                                                    const char *dirname);
+static void     cached_dir_unref                  (CachedDir *dir);
+static CachedDir * cached_dir_add_subdir          (CachedDir  *dir,
+                                                   const char *basename,
+                                                   const char *path);
+static gboolean cached_dir_remove_subdir          (CachedDir  *dir,
+                                                   const char *basename);
 
 static void handle_cached_dir_changed (MenuMonitor      *monitor,
                                       MenuMonitorEvent  event,
@@ -91,18 +100,39 @@ static void handle_cached_dir_changed (MenuMonitor      *monitor,
 
 static CachedDir *dir_cache = NULL;
 
+static void
+clear_cache (CachedDir *dir,
+             gpointer  *cache)
+{
+  *cache = NULL;
+}
+
 static CachedDir *
 cached_dir_new (const char *name)
 {
   CachedDir *dir;
 
   dir = g_new0 (CachedDir, 1);
-
   dir->name = g_strdup (name);
 
   return dir;
 }
 
+static CachedDir *
+cached_dir_new_full (const char *name,
+                     GFunc       notify,
+                     gpointer    notify_data)
+{
+  CachedDir *dir;
+
+  dir = cached_dir_new (name);
+
+  dir->notify = notify;
+  dir->notify_data = notify_data;
+
+  return dir;
+}
+
 static void
 cached_dir_free (CachedDir *dir)
 {
@@ -126,7 +156,7 @@ cached_dir_free (CachedDir *dir)
   dir->entries = NULL;
 
   g_slist_foreach (dir->subdirs,
-                   (GFunc) cached_dir_free,
+                   (GFunc) cached_dir_unref,
                    NULL);
   g_slist_free (dir->subdirs);
   dir->subdirs = NULL;
@@ -135,6 +165,32 @@ cached_dir_free (CachedDir *dir)
   g_free (dir);
 }
 
+static CachedDir *
+cached_dir_ref (CachedDir *dir)
+{
+  dir->references++;
+  return dir;
+}
+
+static void
+cached_dir_unref (CachedDir *dir)
+{
+  if (--dir->references)
+    {
+      CachedDir *parent;
+
+      parent = dir->parent;
+
+      if (parent != NULL)
+        cached_dir_remove_subdir (parent, dir->name);
+
+      if (dir->notify)
+        dir->notify (dir, dir->notify_data);
+
+      cached_dir_free (dir);
+    }
+}
+
 static inline CachedDir *
 find_subdir (CachedDir  *dir,
              const char *subdir)
@@ -213,7 +269,9 @@ cached_dir_lookup (const char *canonical)
   int         i;
 
   if (dir_cache == NULL)
-    dir_cache = cached_dir_new ("/");
+    dir_cache = cached_dir_new_full ("/",
+                                     (GFunc) clear_cache,
+                                     &dir_cache);
   dir = dir_cache;
 
   g_assert (canonical != NULL && canonical[0] == G_DIR_SEPARATOR);
@@ -227,12 +285,7 @@ cached_dir_lookup (const char *canonical)
     {
       CachedDir *subdir;
 
-      if ((subdir = find_subdir (dir, split[i])) == NULL)
-        {
-          subdir = cached_dir_new (split[i]);
-          dir->subdirs = g_slist_prepend (dir->subdirs, subdir);
-          subdir->parent = dir;
-        }
+      subdir = cached_dir_add_subdir (dir, split[i], NULL);
 
       dir = subdir;
 
@@ -310,7 +363,7 @@ cached_dir_remove_entry (CachedDir  *dir,
   return FALSE;
 }
 
-static gboolean
+static CachedDir *
 cached_dir_add_subdir (CachedDir  *dir,
                        const char *basename,
                        const char *path)
@@ -322,23 +375,23 @@ cached_dir_add_subdir (CachedDir  *dir,
   if (subdir != NULL)
     {
       subdir->deleted = FALSE;
-      return TRUE;
+      return subdir;
     }
 
   subdir = cached_dir_new (basename);
 
-  if (!cached_dir_load_entries_recursive (subdir, path))
+  if (path != NULL && !cached_dir_load_entries_recursive (subdir, path))
     {
       cached_dir_free (subdir);
-      return FALSE;
+      return NULL;
     }
 
   menu_verbose ("Caching dir \"%s\"\n", basename);
 
   subdir->parent = dir;
-  dir->subdirs = g_slist_prepend (dir->subdirs, subdir);
+  dir->subdirs = g_slist_prepend (dir->subdirs, cached_dir_ref (subdir));
 
-  return TRUE;
+  return subdir;
 }
 
 static gboolean
@@ -355,7 +408,7 @@ cached_dir_remove_subdir (CachedDir  *dir,
 
       if (subdir->references == 0)
         {
-          cached_dir_free (subdir);
+          cached_dir_unref (subdir);
           dir->subdirs = g_slist_remove (dir->subdirs, subdir);
         }
 
@@ -496,7 +549,7 @@ handle_cached_dir_changed (MenuMonitor      *monitor,
       switch (event)
         {
         case MENU_MONITOR_EVENT_CREATED:
-          handled = cached_dir_add_subdir (dir, basename, path);
+          handled = cached_dir_add_subdir (dir, basename, path) != NULL;
           break;
 
         case MENU_MONITOR_EVENT_CHANGED:
@@ -668,7 +721,7 @@ cached_dir_remove_monitor (CachedDir                 *dir,
 static void
 cached_dir_add_reference (CachedDir *dir)
 {
-  dir->references++;
+  cached_dir_ref (dir);
 
   if (dir->parent != NULL)
     {
@@ -683,29 +736,7 @@ cached_dir_remove_reference (CachedDir *dir)
 
   parent = dir->parent;
 
-  if (--dir->references == 0 && dir->deleted)
-    {
-      if (dir->parent != NULL)
-       {
-         GSList *tmp;
-
-         tmp = parent->subdirs;
-         while (tmp != NULL)
-           {
-             CachedDir *subdir = tmp->data;
-
-             if (!strcmp (subdir->name, dir->name))
-               {
-                 parent->subdirs = g_slist_delete_link (parent->subdirs, tmp);
-                 break;
-               }
-
-             tmp = tmp->next;
-           }
-       }
-
-      cached_dir_free (dir);
-    }
+  cached_dir_unref (dir);
 
   if (parent != NULL)
     {
diff --git a/libmenu/gmenu-tree.c b/libmenu/gmenu-tree.c
index 61ca041..9aa94c5 100644
--- a/libmenu/gmenu-tree.c
+++ b/libmenu/gmenu-tree.c
@@ -163,7 +163,7 @@ static void      gmenu_tree_resolve_files        (GMenuTree       *tree,
                                                  MenuLayoutNode  *layout);
 static void      gmenu_tree_force_recanonicalize (GMenuTree       *tree);
 static void      gmenu_tree_invoke_monitors      (GMenuTree       *tree);
-     
+
 static void gmenu_tree_item_unref_and_unset_parent (gpointer itemp);
 
 typedef enum
@@ -1485,7 +1485,7 @@ gmenu_tree_directory_finalize (GMenuTreeDirectory *directory)
                   NULL);
   g_slist_free (directory->contents);
   directory->contents = NULL;
-  
+
   g_slist_foreach (directory->default_layout_info,
                   (GFunc) menu_layout_node_unref,
                   NULL);


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