[glib/wip/gcleanup] gtype: Use a single cleanup function for gtype memory



commit ce1c6aa334cba7d3283bd34169087d19d55c908f
Author: Stef Walter <stefw gnome org>
Date:   Fri Nov 8 08:46:57 2013 +0100

    gtype: Use a single cleanup function for gtype memory
    
    There are a lot of intertwined pointer references between
    types, their vtables, and other bits. Free the memory for them
    all together.
    
    Note that we still do all finalization (ie: callbacks) per type
    and module, in the relevant cleanup lists.

 gobject/gtype.c |  181 +++++++++++++++++++++++++------------------------------
 1 files changed, 82 insertions(+), 99 deletions(-)
---
diff --git a/gobject/gtype.c b/gobject/gtype.c
index 3dd9e6c..8f44c7d 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -202,6 +202,7 @@ static void                             type_iface_vtable_iface_init_Wm (TypeNod
                                                                          TypeNode               *node);
 static gboolean                                type_node_is_a_L                (TypeNode               *node,
                                                                         TypeNode               *iface_node);
+static void                             type_cleanup                    (void);
 
 
 /* --- enumeration --- */
@@ -2443,12 +2444,6 @@ type_data_unref_U (TypeNode *node,
   } while (!g_atomic_int_compare_and_exchange ((int *) &node->ref_count, current, current - 1));
 }
 
-static void
-cleanup_class_cache_funcs (void)
-{
-  g_free (static_class_cache_funcs);
-}
-
 /**
  * g_type_add_class_cache_func: (skip)
  * @cache_data: data to be passed to @cache_func
@@ -2472,11 +2467,6 @@ g_type_add_class_cache_func (gpointer            cache_data,
   
   G_WRITE_LOCK (&type_rw_lock);
   i = static_n_class_cache_funcs++;
-  if (static_class_cache_funcs == NULL)
-    {
-      g_cleanup_list_push (G_CLEANUP_LIST, (GCleanupFunc)cleanup_class_cache_funcs, NULL,
-                           G_CLEANUP_PHASE_GRAVEYARD, "cleanup_class_cache_funcs");
-    }
   static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs);
   static_class_cache_funcs[i].cache_data = cache_data;
   static_class_cache_funcs[i].cache_func = cache_func;
@@ -2521,12 +2511,6 @@ g_type_remove_class_cache_func (gpointer            cache_data,
               cache_func, cache_data);
 }
 
-static void
-cleanup_iface_check_funcs (void)
-{
-  g_free (static_iface_check_funcs);
-}
-
 /**
  * g_type_add_interface_check: (skip)
  * @check_data: data to pass to @check_func
@@ -2555,11 +2539,6 @@ g_type_add_interface_check (gpointer                 check_data,
   
   G_WRITE_LOCK (&type_rw_lock);
   i = static_n_iface_check_funcs++;
-  if (static_iface_check_funcs == NULL)
-    {
-      g_cleanup_list_push (G_CLEANUP_LIST, (GCleanupFunc)cleanup_iface_check_funcs, NULL,
-                           G_CLEANUP_PHASE_GRAVEYARD, "cleanup_iface_check_funcs");
-    }
   static_iface_check_funcs = g_renew (IFaceCheckFunc, static_iface_check_funcs, static_n_iface_check_funcs);
   static_iface_check_funcs[i].check_data = check_data;
   static_iface_check_funcs[i].check_func = check_func;
@@ -4392,8 +4371,6 @@ gobject_init_ctor (void)
   
   /* type qname hash table */
   static_type_nodes_ht = g_hash_table_new (g_str_hash, g_str_equal);
-  g_cleanup_list_push (G_CLEANUP_LIST, (GCleanupFunc)g_hash_table_unref, static_type_nodes_ht,
-                       G_CLEANUP_PHASE_GRAVEYARD, "static_type_nodes_ht");
   
   /* invalid type G_TYPE_INVALID (0)
    */
@@ -4454,6 +4431,9 @@ gobject_init_ctor (void)
   /* Signal system
    */
   _g_signal_init ();
+
+  g_cleanup_list_push (G_CLEANUP_LIST, (GCleanupFunc)type_cleanup, NULL,
+                       G_CLEANUP_PHASE_GRAVEYARD, "type_cleanup");
 }
 
 static void
@@ -4965,105 +4945,112 @@ finalize_type (gpointer data)
   node = lookup_type_node_I (type);
   if (node->data && !node->plugin)
     type_data_finalize (node);
+
+  if (node->global_gdata != NULL)
+    {
+      QData *qdatas = node->global_gdata->qdatas;
+      int i;
+
+      for (i = 0; i < node->global_gdata->n_qdatas; i++)
+        {
+          if (qdatas[i].destroy)
+            {
+              qdatas[i].destroy (qdatas[i].data);
+              qdatas[i].destroy = NULL;
+              qdatas[i].data = NULL;
+            }
+        }
+    }
 }
 
 static void
-g_type_cleanup (GType type)
+type_cleanup (void)
 {
-  const gchar *name;
-  TypeNode *node;
+  GHashTableIter iter;
+  gpointer value;
+  GHashTable *vtables;
 
-  node = lookup_type_node_I (type);
+  static_n_class_cache_funcs = 0;
+  g_free (static_class_cache_funcs);
+  static_class_cache_funcs = NULL;
 
-  g_free (node->children);
+  static_n_iface_check_funcs = 0;
+  g_free (static_iface_check_funcs);
+  static_iface_check_funcs = NULL;
 
-  if (node->is_classed)
+  g_hash_table_iter_init (&iter, static_type_nodes_ht);
+  vtables = g_hash_table_new (NULL, NULL);
+  while (g_hash_table_iter_next (&iter, NULL, &value))
     {
-      IFaceEntries *entries;
+      GType gtype = (GType) GPOINTER_TO_SIZE (value);
+      TypeNode *node;
 
-      entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node);
-      if (entries)
+      node = lookup_type_node_I (gtype);
+
+      g_free (node->children);
+
+      if (node->is_classed)
         {
-          guint i;
+          IFaceEntries *entries;
 
-          for (i = 0; i != IFACE_ENTRIES_N_ENTRIES (entries); i++)
+          entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node);
+          if (entries)
             {
-              g_cleanup_list_push (G_CLEANUP_LIST, g_free, entries->entry[i].vtable,
-                                   G_CLEANUP_PHASE_GRAVEYARD, "entries->entry[i].vtable");
-              entries->entry[i].vtable = NULL;
+              guint i;
+
+              for (i = 0; i != IFACE_ENTRIES_N_ENTRIES (entries); i++)
+                g_hash_table_insert (vtables, entries->entry[i].vtable, NULL);
             }
-        }
 
-      _g_atomic_array_free (CLASSED_NODE_IFACES_ENTRIES (node));
+          _g_atomic_array_free (CLASSED_NODE_IFACES_ENTRIES (node));
 
-      if (node->data && node->data->class.class)
-        {
-          g_cleanup_list_push (G_CLEANUP_LIST, g_free, node->data->class.class,
-                               G_CLEANUP_PHASE_GRAVEYARD, "node->data->class.class");
-          node->data->class.class = NULL;
+          if (node->data)
+            g_free (node->data->class.class);
         }
-    }
 
-  if (NODE_IS_IFACE (node))
-    {
-      IFaceHolder *iholder, *next;
-
-      _g_atomic_array_free (&node->_prot.offsets);
-
-      iholder = iface_node_get_holders_L (node);
-      while (iholder)
+      if (NODE_IS_IFACE (node))
         {
-          next = iholder->next;
+          IFaceHolder *iholder, *next;
 
-          g_free (iholder->info);
-          g_free (iholder);
+          _g_atomic_array_free (&node->_prot.offsets);
 
-          iholder = next;
-        }
+          iholder = iface_node_get_holders_L (node);
+          while (iholder)
+            {
+              next = iholder->next;
 
-      if (node->data != NULL)
-        g_free (node->data->iface.dflt_vtable);
+              g_free (iholder->info);
+              g_free (iholder);
 
-      g_free (iface_node_get_dependants_array_L (node));
-    }
+              iholder = next;
+            }
 
-  g_free (node->data);
+          if (node->data != NULL)
+            g_free (node->data->iface.dflt_vtable);
 
-  if (node->global_gdata != NULL)
-    {
-      QData *qdatas = node->global_gdata->qdatas;
-      int i;
-
-      for (i = 0; i < node->global_gdata->n_qdatas; i++)
-        {
-          if (qdatas[i].destroy)
-            qdatas[i].destroy (qdatas[i].data);
+          g_free (iface_node_get_dependants_array_L (node));
         }
-      g_free (qdatas);
-      g_free (node->global_gdata);
-    }
 
-  g_free (node->prerequisites);
+      g_free (node->data);
 
-  if (!node->plugin)
-    {
-      name = g_quark_to_string (node->qname);
-      if (name != NULL)
+      if (node->global_gdata != NULL)
         {
-          if (!g_hash_table_remove (static_type_nodes_ht, name))
-            g_assert_not_reached ();
+          g_free (node->global_gdata->qdatas);
+          g_free (node->global_gdata);
         }
-    }
 
-  if (G_TYPE_IS_FUNDAMENTAL (type))
-    node = G_STRUCT_MEMBER_P (node, -SIZEOF_FUNDAMENTAL_INFO);
-  g_free (node);
-}
+      g_free (node->prerequisites);
 
-static void
-cleanup_type (gpointer data)
-{
-  g_type_cleanup (GPOINTER_TO_SIZE (data));
+      if (G_TYPE_IS_FUNDAMENTAL (gtype))
+        node = G_STRUCT_MEMBER_P (node, -SIZEOF_FUNDAMENTAL_INFO);
+
+      g_free (node);
+    }
+
+  g_hash_table_foreach (vtables, (GHFunc) g_free, NULL);
+  g_hash_table_unref (vtables);
+  g_hash_table_unref (static_type_nodes_ht);
+  static_type_nodes_ht = NULL;
 }
 
 void
@@ -5071,7 +5058,6 @@ g_type_cleanup_push (GCleanupList *cleanup,
                      GType type)
 {
   GCleanupPhase phase;
-  const gchar *name;
 
   /*
    * For types in our own module, we want them finalized before
@@ -5081,19 +5067,16 @@ g_type_cleanup_push (GCleanupList *cleanup,
     phase = G_CLEANUP_PHASE_MAIN;
   else
     phase = G_CLEANUP_PHASE_LATE;
-  name = g_type_name (type);
 
   /*
    * We want all the finalizers called first. They refer to each
    * other so we can't free anything at this point.
    */
   g_cleanup_list_push (cleanup, finalize_type, GSIZE_TO_POINTER (type),
-                       phase, name);
+                       phase, g_type_name (type));
 
   /*
-   * And at the very end memory is freed. At this point we shouldn't
-   * be doing any callbacks.
+   * And at the very end memory is freed. This is all done in one shot
+   * in the graveyard shift, due to intertwined pointers. See type_cleanup().
    */
-  g_cleanup_list_push (cleanup, cleanup_type, GSIZE_TO_POINTER (type),
-                       G_CLEANUP_PHASE_GRAVEYARD, name);
 }


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