[glib/wip/gcleanup: 66/106] gtype: Implement cleanup of GType
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/gcleanup: 66/106] gtype: Implement cleanup of GType
- Date: Mon, 11 Nov 2013 08:00:32 +0000 (UTC)
commit 8b110f591bfd41d90a607bc4866f3b62eb2a5a91
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
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.
https://bugzilla.gnome.org/show_bug.cgi?id=711778
gobject/gtype.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
gobject/gtype.h | 4 +-
2 files changed, 242 insertions(+), 2 deletions(-)
---
diff --git a/gobject/gtype.c b/gobject/gtype.c
index 9ede33c..52d1529 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 --- */
@@ -2510,7 +2511,6 @@ g_type_remove_class_cache_func (gpointer cache_data,
cache_func, cache_data);
}
-
/**
* g_type_add_interface_check: (skip)
* @check_data: data to pass to @check_func
@@ -4430,6 +4430,92 @@ gobject_init_ctor (void)
/* Signal system
*/
_g_signal_init ();
+
+ G_CLEANUP_FUNC_IN_PHASE (type_cleanup, G_CLEANUP_PHASE_GRAVEYARD);
+}
+
+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);
+ }
}
/**
@@ -4847,3 +4933,155 @@ 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);
+
+ 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;
+ }
+ }
+ }
+
+ if (NODE_IS_IFACE (node))
+ {
+ _g_signals_destroy (type);
+ }
+}
+
+static void
+type_cleanup (void)
+{
+ GHashTableIter iter;
+ gpointer value;
+ GHashTable *vtables;
+
+ static_n_class_cache_funcs = 0;
+ g_free (static_class_cache_funcs);
+ static_class_cache_funcs = NULL;
+
+ static_n_iface_check_funcs = 0;
+ g_free (static_iface_check_funcs);
+ static_iface_check_funcs = NULL;
+
+ 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))
+ {
+ GType gtype = (GType) GPOINTER_TO_SIZE (value);
+ TypeNode *node;
+
+ node = lookup_type_node_I (gtype);
+
+ 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_hash_table_insert (vtables, entries->entry[i].vtable, NULL);
+ }
+
+ _g_atomic_array_free (CLASSED_NODE_IFACES_ENTRIES (node));
+
+ 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)
+ {
+ 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)
+ {
+ g_free (node->global_gdata->qdatas);
+ g_free (node->global_gdata);
+ }
+
+ g_free (node->prerequisites);
+
+ 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;
+
+ _g_atomic_array_cleanup ();
+}
+
+void
+g_type_cleanup_push (GType type,
+ GCleanupList *cleanup)
+{
+ gint phase;
+
+ /*
+ * For types in our own module, we want them finalized before
+ * the above infrastructure.
+ */
+ if (cleanup == G_CLEANUP_SCOPE)
+ phase = G_CLEANUP_PHASE_DEFAULT;
+ else
+ phase = G_CLEANUP_PHASE_LATE;
+
+ /*
+ * 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, phase, finalize_type,
+ GSIZE_TO_POINTER (type), g_type_name (type));
+
+ /*
+ * 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().
+ */
+}
diff --git a/gobject/gtype.h b/gobject/gtype.h
index ca6bc66..d498c11 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 (GType type,
+ GCleanupList *cleanup);
/* --- type registration --- */
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]