mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 15:36:14 +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
|
||||
iface_node_has_available_offset_L (TypeNode *iface_node,
|
||||
int offset,
|
||||
@ -2816,6 +2831,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);
|
||||
@ -2826,34 +2843,39 @@ 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 */
|
||||
|
||||
/* we need an initialized parent class for initializing derived classes */
|
||||
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 */
|
||||
{
|
||||
/* we need an initialized parent class for initializing derived classes */
|
||||
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);
|
||||
if (pclass)
|
||||
g_type_class_unref (pclass);
|
||||
}
|
||||
type_class_init_Wm (node, pclass);
|
||||
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
|
||||
if (pclass)
|
||||
g_type_class_unref (pclass);
|
||||
|
||||
g_static_rec_mutex_unlock (&class_init_rec_mutex);
|
||||
|
||||
return node->data->class.class;
|
||||
|
Loading…
Reference in New Issue
Block a user