[glib/wip/gcleanup] gtype: Implement cleanup of GType
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/gcleanup] gtype: Implement cleanup of GType
- Date: Thu, 7 Nov 2013 22:03:31 +0000 (UTC)
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]