[glib/gobject-performance] Add type_data_ref_U() and use it in g_type_class_ref()
- From: Benjamin Otte <otte src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [glib/gobject-performance] Add type_data_ref_U() and use it in g_type_class_ref()
- Date: Thu, 24 Sep 2009 11:31:00 +0000 (UTC)
commit 4659a983ea1a2518c06b3f565512a12dddf84e89
Author: Edward Hervey <bilboed bilboed com>
Date: Thu Sep 24 12:42:49 2009 +0200
Add type_data_ref_U() and use it in g_type_class_ref()
The function returns TRUE if the type was previously initialized and can
be easily reused. It returns FALSE and does not take a reference if the
type is not referenced yet.
g_type_class_ref() uses this to avoid taking locks in the common path,
which speeds up object creation a lot - in particular in multithreaded
applications.
https://bugzilla.gnome.org/show_bug.cgi?id=585375
gobject/gtype.c | 54 ++++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 42 insertions(+), 12 deletions(-)
---
diff --git a/gobject/gtype.c b/gobject/gtype.c
index b5d44f0..c4840bc 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -1201,6 +1201,21 @@ type_data_ref_Wm (TypeNode *node)
}
}
+static inline gboolean
+type_data_ref_U (TypeNode *node)
+{
+ guint current;
+
+ do {
+ current = NODE_REFCOUNT (node);
+
+ if (current < 1)
+ return FALSE;
+ } while (!g_atomic_int_compare_and_exchange ((int *) &node->ref_count, current, current + 1));
+
+ return TRUE;
+}
+
static gboolean
iface_node_has_available_offset_L (TypeNode *iface_node,
int offset,
@@ -2814,6 +2829,8 @@ g_type_class_ref (GType type)
{
TypeNode *node;
GType ptype;
+ gboolean holds_ref;
+ GTypeClass *pclass;
/* optimize for common code path */
node = lookup_type_node_I (type);
@@ -2824,32 +2841,45 @@ g_type_class_ref (GType type)
return NULL;
}
- G_WRITE_LOCK (&type_rw_lock);
- type_data_ref_Wm (node);
- if (g_atomic_int_get (&node->data->class.init_state) == INITIALIZED)
+ if (G_LIKELY (type_data_ref_U (node)))
{
- G_WRITE_UNLOCK (&type_rw_lock);
- return node->data->class.class;
+ if (G_LIKELY (g_atomic_int_get (&node->data->class.init_state) == INITIALIZED))
+ return node->data->class.class;
+ holds_ref = TRUE;
}
- ptype = NODE_PARENT_TYPE (node);
- G_WRITE_UNLOCK (&type_rw_lock);
-
- g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
+ else
+ holds_ref = FALSE;
+
/* here, we either have node->data->class.class == NULL, or a recursive
* call to g_type_class_ref() with a partly initialized class, or
* node->data->class.init_state == INITIALIZED, because any
* concurrently running initialization was guarded by class_init_rec_mutex.
*/
+ g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
+
+ /* acquire reference on parent class */
+ ptype = NODE_PARENT_TYPE (node);
+ pclass = ptype ? g_type_class_ref (ptype) : NULL;
+
+ G_WRITE_LOCK (&type_rw_lock);
+
+ if (!holds_ref)
+ type_data_ref_Wm (node);
+
if (!node->data->class.class) /* class uninitialized */
{
- /* acquire reference on parent class */
- GTypeClass *pclass = ptype ? g_type_class_ref (ptype) : NULL;
- G_WRITE_LOCK (&type_rw_lock);
if (node->data->class.class) /* class was initialized during parent class initialization? */
INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
type_class_init_Wm (node, pclass);
G_WRITE_UNLOCK (&type_rw_lock);
}
+ else
+ {
+ /* release ref to parent class, it wasn't needed */
+ G_WRITE_UNLOCK (&type_rw_lock);
+ g_type_class_unref (pclass);
+ }
+
g_static_rec_mutex_unlock (&class_init_rec_mutex);
return node->data->class.class;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]