mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-27 16:06:16 +01:00
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
This commit is contained in:
parent
5160175656
commit
35c376a8a6
@ -1203,6 +1203,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
|
static gboolean
|
||||||
iface_node_has_available_offset_L (TypeNode *iface_node,
|
iface_node_has_available_offset_L (TypeNode *iface_node,
|
||||||
int offset,
|
int offset,
|
||||||
@ -2816,6 +2831,8 @@ g_type_class_ref (GType type)
|
|||||||
{
|
{
|
||||||
TypeNode *node;
|
TypeNode *node;
|
||||||
GType ptype;
|
GType ptype;
|
||||||
|
gboolean holds_ref;
|
||||||
|
GTypeClass *pclass;
|
||||||
|
|
||||||
/* optimize for common code path */
|
/* optimize for common code path */
|
||||||
node = lookup_type_node_I (type);
|
node = lookup_type_node_I (type);
|
||||||
@ -2826,34 +2843,39 @@ g_type_class_ref (GType type)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
G_WRITE_LOCK (&type_rw_lock);
|
if (G_LIKELY (type_data_ref_U (node)))
|
||||||
type_data_ref_Wm (node);
|
|
||||||
if (g_atomic_int_get (&node->data->class.init_state) == INITIALIZED)
|
|
||||||
{
|
{
|
||||||
G_WRITE_UNLOCK (&type_rw_lock);
|
if (G_LIKELY (g_atomic_int_get (&node->data->class.init_state) == INITIALIZED))
|
||||||
return node->data->class.class;
|
return node->data->class.class;
|
||||||
|
holds_ref = TRUE;
|
||||||
}
|
}
|
||||||
ptype = NODE_PARENT_TYPE (node);
|
else
|
||||||
G_WRITE_UNLOCK (&type_rw_lock);
|
holds_ref = FALSE;
|
||||||
|
|
||||||
g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
|
|
||||||
/* here, we either have node->data->class.class == NULL, or a recursive
|
/* here, we either have node->data->class.class == NULL, or a recursive
|
||||||
* call to g_type_class_ref() with a partly initialized class, or
|
* call to g_type_class_ref() with a partly initialized class, or
|
||||||
* node->data->class.init_state == INITIALIZED, because any
|
* node->data->class.init_state == INITIALIZED, because any
|
||||||
* concurrently running initialization was guarded by class_init_rec_mutex.
|
* concurrently running initialization was guarded by class_init_rec_mutex.
|
||||||
*/
|
*/
|
||||||
if (!node->data->class.class) /* class uninitialized */
|
g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
|
||||||
{
|
|
||||||
/* we need an initialized parent class for initializing derived classes */
|
/* we need an initialized parent class for initializing derived classes */
|
||||||
GTypeClass *pclass = ptype ? g_type_class_ref (ptype) : NULL;
|
ptype = NODE_PARENT_TYPE (node);
|
||||||
|
pclass = ptype ? g_type_class_ref (ptype) : NULL;
|
||||||
|
|
||||||
G_WRITE_LOCK (&type_rw_lock);
|
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));
|
if (!holds_ref)
|
||||||
|
type_data_ref_Wm (node);
|
||||||
|
|
||||||
|
if (!node->data->class.class) /* class uninitialized */
|
||||||
type_class_init_Wm (node, pclass);
|
type_class_init_Wm (node, pclass);
|
||||||
|
|
||||||
G_WRITE_UNLOCK (&type_rw_lock);
|
G_WRITE_UNLOCK (&type_rw_lock);
|
||||||
|
|
||||||
if (pclass)
|
if (pclass)
|
||||||
g_type_class_unref (pclass);
|
g_type_class_unref (pclass);
|
||||||
}
|
|
||||||
g_static_rec_mutex_unlock (&class_init_rec_mutex);
|
g_static_rec_mutex_unlock (&class_init_rec_mutex);
|
||||||
|
|
||||||
return node->data->class.class;
|
return node->data->class.class;
|
||||||
|
Loading…
Reference in New Issue
Block a user