[glib/wip/gcleanup] gtype: Implement cleanup of GType



commit ce6d3daf41380a2e75989f10ed6a8495dfce66ca
Author: Stef Walter <stefw gnome org>
Date:   Thu Nov 7 22:49:17 2013 +0100

    gtype: Implement cleanup of GType
    
    Partially from patches from Ole André Vadla Ravnås, and Dan Winship

 gobject/gtype.c |  253 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gobject/gtype.h |    4 +-
 2 files changed, 254 insertions(+), 3 deletions(-)
---
diff --git a/gobject/gtype.c b/gobject/gtype.c
index 122d751..6cab710 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -261,9 +261,9 @@ struct _TypeNode
 #define        IFACE_NODE_N_PREREQUISITES(node)        ((node)->n_prerequisites)
 #define        IFACE_NODE_PREREQUISITES(node)          ((node)->prerequisites)
 #define        iface_node_get_holders_L(node)          ((IFaceHolder*) type_get_qdata_L ((node), 
static_quark_iface_holder))
-#define        iface_node_set_holders_W(node, holders) (type_set_qdata_W ((node), static_quark_iface_holder, 
(holders)))
+#define        iface_node_set_holders_W(node, holders) (type_set_qdata_W ((node), static_quark_iface_holder, 
(holders), NULL))
 #define        iface_node_get_dependants_array_L(n)    ((GType*) type_get_qdata_L ((n), 
static_quark_dependants_array))
-#define        iface_node_set_dependants_array_W(n,d)  (type_set_qdata_W ((n), 
static_quark_dependants_array, (d)))
+#define        iface_node_set_dependants_array_W(n,d)  (type_set_qdata_W ((n), 
static_quark_dependants_array, (d), NULL))
 #define        TYPE_ID_MASK                            ((GType) ((1 << G_TYPE_FUNDAMENTAL_SHIFT) - 1))
 
 #define NODE_IS_ANCESTOR(ancestor, node)                                                    \
@@ -2443,6 +2443,12 @@ 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
@@ -2466,6 +2472,11 @@ 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;
@@ -2510,6 +2521,11 @@ 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)
@@ -2539,6 +2555,11 @@ 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;
@@ -4372,6 +4393,8 @@ 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)
    */
@@ -4432,6 +4455,90 @@ gobject_init_ctor (void)
   _g_signal_init ();
 }
 
+static void
+type_iface_vtable_finalize (TypeNode       *iface,
+                           TypeNode       *node,
+                           GTypeInterface *vtable)
+{
+  IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
+  IFaceHolder *iholder;
+
+  iholder = type_iface_retrieve_holder_info_Wm (iface, NODE_TYPE (node), FALSE);
+  if (!iholder)
+    return;
+
+  g_assert (entry && entry->vtable == vtable && iholder->info);
+
+  g_assert (entry->init_state == INITIALIZED);
+  entry->init_state = UNINITIALIZED;
+
+  if (iholder->info->interface_finalize)
+    iholder->info->interface_finalize (vtable, iholder->info->interface_data);
+  if (iface->data->iface.vtable_finalize_base)
+    iface->data->iface.vtable_finalize_base (vtable);
+}
+
+static void
+type_data_finalize_class_ifaces (TypeNode *node)
+{
+  IFaceEntries *entries;
+  guint i;
+
+  entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node);
+  for (i = 0; entries != NULL && i < IFACE_ENTRIES_N_ENTRIES (entries); i++)
+    {
+      IFaceEntry *entry = &entries->entry[i];
+      if (entry->vtable)
+       {
+          g_assert (entry->init_state == INITIALIZED);
+
+          type_iface_vtable_finalize (lookup_type_node_I (entry->iface_type), node, entry->vtable);
+
+          entry->init_state = UNINITIALIZED;
+       }
+    }
+}
+
+static void
+type_data_finalize_class (TypeNode  *node,
+                         ClassData *cdata)
+{
+  GTypeClass *class = cdata->class;
+  TypeNode *bnode;
+
+  if (cdata->class_finalize)
+      cdata->class_finalize (class, (gpointer) cdata->class_data);
+
+  /* call all base class destruction functions in descending order
+   */
+  if (cdata->class_finalize_base)
+    cdata->class_finalize_base (class);
+  for (bnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); bnode; bnode = lookup_type_node_I 
(NODE_PARENT_TYPE (bnode)))
+    if (bnode->data->class.class_finalize_base)
+      bnode->data->class.class_finalize_base (class);
+}
+
+static void
+type_data_finalize (TypeNode *node)
+{
+  TypeData *tdata;
+
+  tdata = node->data;
+  if (node->is_classed && tdata->class.class)
+    {
+      if (CLASSED_NODE_IFACES_ENTRIES_LOCKED (node) != NULL)
+       type_data_finalize_class_ifaces (node);
+      type_data_finalize_class (node, &tdata->class);
+    }
+  else if (NODE_IS_IFACE (node) && tdata->iface.dflt_vtable)
+    {
+      if (tdata->iface.dflt_finalize)
+        tdata->iface.dflt_finalize (tdata->iface.dflt_vtable, (gpointer) tdata->iface.dflt_data);
+      if (tdata->iface.vtable_finalize_base)
+        tdata->iface.vtable_finalize_base (tdata->iface.dflt_vtable);
+    }
+}
+
 /**
  * g_type_class_add_private:
  * @g_class: class structure for an instantiatable type
@@ -4847,3 +4954,145 @@ g_type_is_in_init (GType type)
 
   return node->data->class.init_state != INITIALIZED;
 }
+
+static void
+finalize_type (gpointer data)
+{
+  GType type = GPOINTER_TO_SIZE (data);
+  TypeNode *node;
+
+  node = lookup_type_node_I (type);
+  if (node->data && !node->plugin)
+    type_data_finalize (node);
+}
+
+static void
+g_type_cleanup (GType type)
+{
+  const gchar *name;
+  TypeNode *node;
+
+  node = lookup_type_node_I (type);
+
+  g_free (node->children);
+
+  if (node->is_classed)
+    {
+      IFaceEntries *entries;
+
+      entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node);
+      if (entries)
+        {
+          guint i;
+
+          for (i = 0; i != IFACE_ENTRIES_N_ENTRIES (entries); i++)
+            {
+              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;
+            }
+        }
+
+      _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_IS_IFACE (node))
+    {
+      IFaceHolder *iholder, *next;
+
+      _g_atomic_array_free (&node->_prot.offsets);
+
+      iholder = iface_node_get_holders_L (node);
+      while (iholder)
+        {
+          next = iholder->next;
+
+          g_free (iholder->info);
+          g_free (iholder);
+
+          iholder = next;
+        }
+
+      if (node->data != NULL)
+        g_free (node->data->iface.dflt_vtable);
+
+      g_free (iface_node_get_dependants_array_L (node));
+    }
+
+  g_free (node->data);
+
+  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 (qdatas);
+      g_free (node->global_gdata);
+    }
+
+  g_free (node->prerequisites);
+
+  if (!node->plugin)
+    {
+      name = g_quark_to_string (node->qname);
+      if (name != NULL)
+        {
+          if (!g_hash_table_remove (static_type_nodes_ht, name))
+            g_assert_not_reached ();
+        }
+    }
+
+  if (G_TYPE_IS_FUNDAMENTAL (type))
+    node = G_STRUCT_MEMBER_P (node, -SIZEOF_FUNDAMENTAL_INFO);
+  g_free (node);
+}
+
+static void
+cleanup_type (gpointer data)
+{
+  g_type_cleanup (GPOINTER_TO_SIZE (data));
+}
+
+void
+g_type_cleanup_push (GCleanupList *cleanup,
+                     GType type)
+{
+  GCleanupPhase phase;
+  const gchar *name;
+
+  /*
+   * For types in our own module, we want them finalized before
+   * the above infrastructure.
+   */
+  if (cleanup == G_CLEANUP_LIST)
+    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);
+
+  /*
+   * And at the very end memory is freed. At this point we shouldn't
+   * be doing any callbacks.
+   */
+  g_cleanup_list_push (cleanup, cleanup_type, GSIZE_TO_POINTER (type),
+                       G_CLEANUP_PHASE_GRAVEYARD, name);
+}
diff --git a/gobject/gtype.h b/gobject/gtype.h
index ca6bc66..7522d06 100644
--- a/gobject/gtype.h
+++ b/gobject/gtype.h
@@ -732,7 +732,9 @@ gpointer              g_type_get_qdata               (GType            type,
 GLIB_AVAILABLE_IN_ALL
 void                 g_type_query                   (GType            type,
                                                      GTypeQuery      *query);
-
+GLIB_AVAILABLE_IN_2_40
+void                  g_type_cleanup_push            (GCleanupList    *cleanup,
+                                                      GType            type);
 
 /* --- type registration --- */
 /**


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