mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-10 12:55:48 +01:00
Merge branch 'ebassi/gtype-refcount' into 'main'
Drop TypeNode reference counting See merge request GNOME/glib!3255
This commit is contained in:
commit
cac9100960
568
gobject/gtype.c
568
gobject/gtype.c
@ -153,10 +153,6 @@ static void type_data_make_W (TypeNode *node,
|
||||
const GTypeInfo *info,
|
||||
const GTypeValueTable *value_table);
|
||||
static inline void type_data_ref_Wm (TypeNode *node);
|
||||
static inline void type_data_unref_U (TypeNode *node,
|
||||
gboolean uncached);
|
||||
static void type_data_last_unref_Wm (TypeNode * node,
|
||||
gboolean uncached);
|
||||
static inline gpointer type_get_qdata_L (TypeNode *node,
|
||||
GQuark quark);
|
||||
static inline void type_set_qdata_W (TypeNode *node,
|
||||
@ -192,7 +188,6 @@ typedef enum
|
||||
/* --- structures --- */
|
||||
struct _TypeNode
|
||||
{
|
||||
guint ref_count; /* (atomic) */
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
guint instance_count; /* (atomic) */
|
||||
#endif
|
||||
@ -228,7 +223,6 @@ struct _TypeNode
|
||||
#define NODE_PARENT_TYPE(node) (node->supers[1])
|
||||
#define NODE_FUNDAMENTAL_TYPE(node) (node->supers[node->n_supers])
|
||||
#define NODE_NAME(node) (g_quark_to_string (node->qname))
|
||||
#define NODE_REFCOUNT(node) ((guint) g_atomic_int_get ((int *) &(node)->ref_count))
|
||||
#define NODE_IS_BOXED(node) (NODE_FUNDAMENTAL_TYPE (node) == G_TYPE_BOXED)
|
||||
#define NODE_IS_IFACE(node) (NODE_FUNDAMENTAL_TYPE (node) == G_TYPE_INTERFACE)
|
||||
#define CLASSED_NODE_IFACES_ENTRIES(node) (&(node)->_prot.iface_entries)
|
||||
@ -297,7 +291,7 @@ struct _ClassData
|
||||
CommonData common;
|
||||
guint16 class_size;
|
||||
guint16 class_private_size;
|
||||
int init_state; /* (atomic) - g_type_class_ref reads it unlocked */
|
||||
int init_state; /* (atomic) - g_type_class_get reads it unlocked */
|
||||
GBaseInitFunc class_init_base;
|
||||
GBaseFinalizeFunc class_finalize_base;
|
||||
GClassInitFunc class_init;
|
||||
@ -311,7 +305,7 @@ struct _InstanceData
|
||||
CommonData common;
|
||||
guint16 class_size;
|
||||
guint16 class_private_size;
|
||||
int init_state; /* (atomic) - g_type_class_ref reads it unlocked */
|
||||
int init_state; /* (atomic) - g_type_class_get reads it unlocked */
|
||||
GBaseInitFunc class_init_base;
|
||||
GBaseFinalizeFunc class_finalize_base;
|
||||
GClassInitFunc class_init;
|
||||
@ -1204,7 +1198,7 @@ type_data_make_W (TypeNode *node,
|
||||
!((G_TYPE_FLAG_VALUE_ABSTRACT | G_TYPE_FLAG_ABSTRACT) &
|
||||
GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags))));
|
||||
|
||||
g_atomic_int_set ((int *) &node->ref_count, 1);
|
||||
g_assert (node->data->common.value_table != NULL); /* paranoid */
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -1240,27 +1234,6 @@ type_data_ref_Wm (TypeNode *node)
|
||||
check_value_table_I (NODE_NAME (node),
|
||||
&tmp_value_table) ? &tmp_value_table : NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (NODE_REFCOUNT (node) > 0);
|
||||
|
||||
g_atomic_int_inc ((int *) &node->ref_count);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -1776,29 +1749,6 @@ type_iface_retrieve_holder_info_Wm (TypeNode *iface,
|
||||
return iholder; /* we don't modify write lock upon returning NULL */
|
||||
}
|
||||
|
||||
static void
|
||||
type_iface_blow_holder_info_Wm (TypeNode *iface,
|
||||
GType instance_type)
|
||||
{
|
||||
IFaceHolder *iholder = iface_node_get_holders_L (iface);
|
||||
|
||||
g_assert (NODE_IS_IFACE (iface));
|
||||
|
||||
while (iholder->instance_type != instance_type)
|
||||
iholder = iholder->next;
|
||||
|
||||
if (iholder->info && iholder->plugin)
|
||||
{
|
||||
g_free (iholder->info);
|
||||
iholder->info = NULL;
|
||||
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
g_type_plugin_unuse (iholder->plugin);
|
||||
type_data_unref_U (iface, FALSE);
|
||||
G_WRITE_LOCK (&type_rw_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_issue_deprecation_warning (GType type)
|
||||
{
|
||||
@ -1892,7 +1842,7 @@ g_type_create_instance (GType type)
|
||||
maybe_issue_deprecation_warning (type);
|
||||
}
|
||||
|
||||
class = g_type_class_ref (type);
|
||||
class = g_type_class_get (type);
|
||||
|
||||
/* We allocate the 'private' areas before the normal instance data, in
|
||||
* reverse order. This allows the private area of a particular class
|
||||
@ -2035,8 +1985,6 @@ g_type_free_instance (GTypeInstance *instance)
|
||||
g_atomic_int_add ((int *) &node->instance_count, -1);
|
||||
}
|
||||
#endif
|
||||
|
||||
g_type_class_unref (class);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2159,41 +2107,6 @@ type_iface_vtable_iface_init_Wm (TypeNode *iface,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
type_iface_vtable_finalize_Wm (TypeNode *iface,
|
||||
TypeNode *node,
|
||||
GTypeInterface *vtable)
|
||||
{
|
||||
IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
|
||||
IFaceHolder *iholder;
|
||||
|
||||
/* type_iface_retrieve_holder_info_Wm() doesn't modify write lock for returning NULL */
|
||||
iholder = type_iface_retrieve_holder_info_Wm (iface, NODE_TYPE (node), FALSE);
|
||||
if (!iholder)
|
||||
return FALSE; /* we don't modify write lock upon FALSE */
|
||||
|
||||
g_assert (entry && entry->vtable == vtable && iholder->info);
|
||||
|
||||
entry->vtable = NULL;
|
||||
entry->init_state = UNINITIALIZED;
|
||||
if (iholder->info->interface_finalize || iface->data->iface.vtable_finalize_base)
|
||||
{
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
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);
|
||||
G_WRITE_LOCK (&type_rw_lock);
|
||||
}
|
||||
vtable->g_type = 0;
|
||||
vtable->g_instance_type = 0;
|
||||
g_free (vtable);
|
||||
|
||||
type_iface_blow_holder_info_Wm (iface, NODE_TYPE (node));
|
||||
|
||||
return TRUE; /* write lock modified */
|
||||
}
|
||||
|
||||
static void
|
||||
type_class_init_Wm (TypeNode *node,
|
||||
GTypeClass *pclass)
|
||||
@ -2354,193 +2267,6 @@ type_class_init_Wm (TypeNode *node,
|
||||
g_atomic_int_set (&node->data->class.init_state, INITIALIZED);
|
||||
}
|
||||
|
||||
static void
|
||||
type_data_finalize_class_ifaces_Wm (TypeNode *node)
|
||||
{
|
||||
guint i;
|
||||
IFaceEntries *entries;
|
||||
|
||||
g_assert (node->is_instantiatable && node->data && node->data->class.class && NODE_REFCOUNT (node) == 0);
|
||||
|
||||
reiterate:
|
||||
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)
|
||||
{
|
||||
if (type_iface_vtable_finalize_Wm (lookup_type_node_I (entry->iface_type), node, entry->vtable))
|
||||
{
|
||||
/* refetch entries, IFACES_ENTRIES might be modified */
|
||||
goto reiterate;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* type_iface_vtable_finalize_Wm() doesn't modify write lock upon FALSE,
|
||||
* iface vtable came from parent
|
||||
*/
|
||||
entry->vtable = NULL;
|
||||
entry->init_state = UNINITIALIZED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
type_data_finalize_class_U (TypeNode *node,
|
||||
ClassData *cdata)
|
||||
{
|
||||
GTypeClass *class = cdata->class;
|
||||
TypeNode *bnode;
|
||||
|
||||
g_assert (cdata->class && NODE_REFCOUNT (node) == 0);
|
||||
|
||||
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);
|
||||
|
||||
g_free (cdata->class);
|
||||
}
|
||||
|
||||
static void
|
||||
type_data_last_unref_Wm (TypeNode *node,
|
||||
gboolean uncached)
|
||||
{
|
||||
g_return_if_fail (node != NULL && node->plugin != NULL);
|
||||
|
||||
if (!node->data || NODE_REFCOUNT (node) == 0)
|
||||
{
|
||||
g_critical ("cannot drop last reference to unreferenced type '%s'",
|
||||
NODE_NAME (node));
|
||||
return;
|
||||
}
|
||||
|
||||
/* call class cache hooks */
|
||||
if (node->is_classed && node->data && node->data->class.class && static_n_class_cache_funcs && !uncached)
|
||||
{
|
||||
guint i;
|
||||
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
G_READ_LOCK (&type_rw_lock);
|
||||
for (i = 0; i < static_n_class_cache_funcs; i++)
|
||||
{
|
||||
GTypeClassCacheFunc cache_func = static_class_cache_funcs[i].cache_func;
|
||||
gpointer cache_data = static_class_cache_funcs[i].cache_data;
|
||||
gboolean need_break;
|
||||
|
||||
G_READ_UNLOCK (&type_rw_lock);
|
||||
need_break = cache_func (cache_data, node->data->class.class);
|
||||
G_READ_LOCK (&type_rw_lock);
|
||||
if (!node->data || NODE_REFCOUNT (node) == 0)
|
||||
INVALID_RECURSION ("GType class cache function ", cache_func, NODE_NAME (node));
|
||||
if (need_break)
|
||||
break;
|
||||
}
|
||||
G_READ_UNLOCK (&type_rw_lock);
|
||||
G_WRITE_LOCK (&type_rw_lock);
|
||||
}
|
||||
|
||||
/* may have been re-referenced meanwhile */
|
||||
if (g_atomic_int_dec_and_test ((int *) &node->ref_count))
|
||||
{
|
||||
GType ptype = NODE_PARENT_TYPE (node);
|
||||
TypeData *tdata;
|
||||
|
||||
if (node->is_instantiatable)
|
||||
{
|
||||
/* destroy node->data->instance.mem_chunk */
|
||||
}
|
||||
|
||||
tdata = node->data;
|
||||
if (node->is_classed && tdata->class.class)
|
||||
{
|
||||
if (CLASSED_NODE_IFACES_ENTRIES_LOCKED (node) != NULL)
|
||||
type_data_finalize_class_ifaces_Wm (node);
|
||||
node->mutatable_check_cache = FALSE;
|
||||
node->data = NULL;
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
type_data_finalize_class_U (node, &tdata->class);
|
||||
G_WRITE_LOCK (&type_rw_lock);
|
||||
}
|
||||
else if (NODE_IS_IFACE (node) && tdata->iface.dflt_vtable)
|
||||
{
|
||||
node->mutatable_check_cache = FALSE;
|
||||
node->data = NULL;
|
||||
if (tdata->iface.dflt_finalize || tdata->iface.vtable_finalize_base)
|
||||
{
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
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_WRITE_LOCK (&type_rw_lock);
|
||||
}
|
||||
g_free (tdata->iface.dflt_vtable);
|
||||
}
|
||||
else
|
||||
{
|
||||
node->mutatable_check_cache = FALSE;
|
||||
node->data = NULL;
|
||||
}
|
||||
|
||||
/* freeing tdata->common.value_table and its contents is taken care of
|
||||
* by allocating it in one chunk with tdata
|
||||
*/
|
||||
g_free (tdata);
|
||||
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
g_type_plugin_unuse (node->plugin);
|
||||
if (ptype)
|
||||
type_data_unref_U (lookup_type_node_I (ptype), FALSE);
|
||||
G_WRITE_LOCK (&type_rw_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
type_data_unref_U (TypeNode *node,
|
||||
gboolean uncached)
|
||||
{
|
||||
guint current;
|
||||
|
||||
do {
|
||||
current = NODE_REFCOUNT (node);
|
||||
|
||||
if (current <= 1)
|
||||
{
|
||||
if (!node->plugin)
|
||||
{
|
||||
g_critical ("static type '%s' unreferenced too often",
|
||||
NODE_NAME (node));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is the last reference of a type from a plugin. We are
|
||||
* experimentally disabling support for unloading type
|
||||
* plugins, so don't allow the last ref to drop.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (current > 0);
|
||||
|
||||
g_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
|
||||
G_WRITE_LOCK (&type_rw_lock);
|
||||
type_data_last_unref_Wm (node, uncached);
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
g_rec_mutex_unlock (&class_init_rec_mutex);
|
||||
return;
|
||||
}
|
||||
} while (!g_atomic_int_compare_and_exchange ((int *) &node->ref_count, current, current - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* g_type_add_class_cache_func: (skip)
|
||||
* @cache_data: data to be passed to @cache_func
|
||||
@ -2977,23 +2703,28 @@ g_type_add_interface_dynamic (GType instance_type,
|
||||
|
||||
|
||||
/* --- public API functions --- */
|
||||
|
||||
/**
|
||||
* g_type_class_ref:
|
||||
* g_type_class_get:
|
||||
* @type: type ID of a classed type
|
||||
*
|
||||
* Increments the reference count of the class structure belonging to
|
||||
* @type. This function will demand-create the class if it doesn't
|
||||
* exist already.
|
||||
* Retrieves the type class of the given @type.
|
||||
*
|
||||
* Returns: (type GObject.TypeClass) (transfer none): the #GTypeClass
|
||||
* structure for the given type ID
|
||||
* This function will create the class on demand if it does not exist
|
||||
* already.
|
||||
*
|
||||
* If you don't want to create the class, use g_type_class_peek() instead.
|
||||
*
|
||||
* Returns: (transfer none) (type GObject.TypeClass): the class structure
|
||||
* for the type
|
||||
*
|
||||
* Since: 2.84
|
||||
*/
|
||||
gpointer
|
||||
g_type_class_ref (GType type)
|
||||
g_type_class_get (GType type)
|
||||
{
|
||||
TypeNode *node;
|
||||
GType ptype;
|
||||
gboolean holds_ref;
|
||||
GTypeClass *pclass;
|
||||
|
||||
/* optimize for common code path */
|
||||
@ -3005,14 +2736,11 @@ g_type_class_ref (GType type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (G_LIKELY (type_data_ref_U (node)))
|
||||
if (G_LIKELY (node->data != NULL))
|
||||
{
|
||||
if (G_LIKELY (g_atomic_int_get (&node->data->class.init_state) == INITIALIZED))
|
||||
return node->data->class.class;
|
||||
holds_ref = TRUE;
|
||||
}
|
||||
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
|
||||
@ -3023,49 +2751,58 @@ g_type_class_ref (GType type)
|
||||
|
||||
/* we need an initialized parent class for initializing derived classes */
|
||||
ptype = NODE_PARENT_TYPE (node);
|
||||
pclass = ptype ? g_type_class_ref (ptype) : NULL;
|
||||
pclass = ptype ? g_type_class_get (ptype) : NULL;
|
||||
|
||||
G_WRITE_LOCK (&type_rw_lock);
|
||||
|
||||
if (!holds_ref)
|
||||
type_data_ref_Wm (node);
|
||||
type_data_ref_Wm (node);
|
||||
|
||||
if (!node->data->class.class) /* class uninitialized */
|
||||
type_class_init_Wm (node, pclass);
|
||||
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
|
||||
if (pclass)
|
||||
g_type_class_unref (pclass);
|
||||
|
||||
g_rec_mutex_unlock (&class_init_rec_mutex);
|
||||
|
||||
return node->data->class.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_type_class_ref:
|
||||
* @type: type ID of a classed type
|
||||
*
|
||||
* Increments the reference count of the class structure belonging to
|
||||
* @type.
|
||||
*
|
||||
* This function will demand-create the class if it doesn't exist already.
|
||||
*
|
||||
* Returns: (type GObject.TypeClass) (transfer none): the #GTypeClass
|
||||
* structure for the given type ID
|
||||
*
|
||||
* Deprecated: 2.84: Use g_type_class_get() instead
|
||||
*/
|
||||
gpointer
|
||||
g_type_class_ref (GType type)
|
||||
{
|
||||
return g_type_class_get (type);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_type_class_unref:
|
||||
* @g_class: (type GObject.TypeClass): a #GTypeClass structure to unref
|
||||
*
|
||||
* Decrements the reference count of the class structure being passed in.
|
||||
*
|
||||
* Once the last reference count of a class has been released, classes
|
||||
* may be finalized by the type system, so further dereferencing of a
|
||||
* class pointer after g_type_class_unref() are invalid.
|
||||
*
|
||||
* Deprecated: 2.84: Type class reference counting has been removed and type
|
||||
* classes now cannot be finalized. This function no longer does anything.
|
||||
*/
|
||||
void
|
||||
g_type_class_unref (gpointer g_class)
|
||||
{
|
||||
TypeNode *node;
|
||||
GTypeClass *class = g_class;
|
||||
|
||||
g_return_if_fail (g_class != NULL);
|
||||
|
||||
node = lookup_type_node_I (class->g_type);
|
||||
if (node && node->is_classed && NODE_REFCOUNT (node))
|
||||
type_data_unref_U (node, FALSE);
|
||||
else
|
||||
g_critical ("cannot unreference class of invalid (unclassed) type '%s'",
|
||||
type_descriptive_name_I (class->g_type));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3073,55 +2810,53 @@ g_type_class_unref (gpointer g_class)
|
||||
* @g_class: (type GObject.TypeClass): a #GTypeClass structure to unref
|
||||
*
|
||||
* A variant of g_type_class_unref() for use in #GTypeClassCacheFunc
|
||||
* implementations. It unreferences a class without consulting the chain
|
||||
* implementations.
|
||||
*
|
||||
* It unreferences a class without consulting the chain
|
||||
* of #GTypeClassCacheFuncs, avoiding the recursion which would occur
|
||||
* otherwise.
|
||||
*
|
||||
* Deprecated: 2.84: Type class reference counting has been removed and type
|
||||
* classes now cannot be finalized. This function no longer does anything.
|
||||
*/
|
||||
void
|
||||
g_type_class_unref_uncached (gpointer g_class)
|
||||
{
|
||||
TypeNode *node;
|
||||
GTypeClass *class = g_class;
|
||||
|
||||
g_return_if_fail (g_class != NULL);
|
||||
|
||||
node = lookup_type_node_I (class->g_type);
|
||||
if (node && node->is_classed && NODE_REFCOUNT (node))
|
||||
type_data_unref_U (node, TRUE);
|
||||
else
|
||||
g_critical ("cannot unreference class of invalid (unclassed) type '%s'",
|
||||
type_descriptive_name_I (class->g_type));
|
||||
}
|
||||
|
||||
/**
|
||||
* g_type_class_peek:
|
||||
* @type: type ID of a classed type
|
||||
*
|
||||
* This function is essentially the same as g_type_class_ref(),
|
||||
* except that the classes reference count isn't incremented.
|
||||
* Retrieves the class for a give type.
|
||||
*
|
||||
* This function is essentially the same as g_type_class_get(),
|
||||
* except that the class may have not been instantiated yet.
|
||||
*
|
||||
* As a consequence, this function may return %NULL if the class
|
||||
* of the type passed in does not currently exist (hasn't been
|
||||
* referenced before).
|
||||
*
|
||||
* Returns: (type GObject.TypeClass) (transfer none): the #GTypeClass
|
||||
* structure for the given type ID or %NULL if the class does not
|
||||
* currently exist
|
||||
* Returns: (type GObject.TypeClass) (transfer none) (nullable): the
|
||||
* #GTypeClass structure for the given type ID or %NULL if the class
|
||||
* does not currently exist
|
||||
*/
|
||||
gpointer
|
||||
g_type_class_peek (GType type)
|
||||
{
|
||||
TypeNode *node;
|
||||
gpointer class;
|
||||
|
||||
node = lookup_type_node_I (type);
|
||||
if (node && node->is_classed && NODE_REFCOUNT (node) &&
|
||||
g_atomic_int_get (&node->data->class.init_state) == INITIALIZED)
|
||||
/* ref_count _may_ be 0 */
|
||||
class = node->data->class.class;
|
||||
else
|
||||
class = NULL;
|
||||
if (node && node->is_classed)
|
||||
{
|
||||
if (node->data == NULL)
|
||||
return NULL;
|
||||
|
||||
if (G_LIKELY (g_atomic_int_get (&node->data->class.init_state) == INITIALIZED))
|
||||
return node->data->class.class;
|
||||
}
|
||||
|
||||
return class;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3131,9 +2866,9 @@ g_type_class_peek (GType type)
|
||||
* A more efficient version of g_type_class_peek() which works only for
|
||||
* static types.
|
||||
*
|
||||
* Returns: (type GObject.TypeClass) (transfer none): the #GTypeClass
|
||||
* structure for the given type ID or %NULL if the class does not
|
||||
* currently exist or is dynamically loaded
|
||||
* Returns: (type GObject.TypeClass) (transfer none) (nullable): the
|
||||
* #GTypeClass structure for the given type ID or %NULL if the class
|
||||
* does not currently exist or is dynamically loaded
|
||||
*
|
||||
* Since: 2.4
|
||||
*/
|
||||
@ -3141,36 +2876,42 @@ gpointer
|
||||
g_type_class_peek_static (GType type)
|
||||
{
|
||||
TypeNode *node;
|
||||
gpointer class;
|
||||
|
||||
node = lookup_type_node_I (type);
|
||||
if (node && node->is_classed && NODE_REFCOUNT (node) &&
|
||||
/* peek only static types: */ node->plugin == NULL &&
|
||||
g_atomic_int_get (&node->data->class.init_state) == INITIALIZED)
|
||||
/* ref_count _may_ be 0 */
|
||||
class = node->data->class.class;
|
||||
else
|
||||
class = NULL;
|
||||
|
||||
return class;
|
||||
if (node && node->is_classed)
|
||||
{
|
||||
if (node->data == NULL)
|
||||
return NULL;
|
||||
|
||||
/* peek only static types */
|
||||
if (node->plugin != NULL)
|
||||
return NULL;
|
||||
|
||||
if (G_LIKELY (g_atomic_int_get (&node->data->class.init_state) == INITIALIZED))
|
||||
return node->data->class.class;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_type_class_peek_parent:
|
||||
* @g_class: (type GObject.TypeClass): the #GTypeClass structure to
|
||||
* retrieve the parent class for
|
||||
* retrieve the parent class for
|
||||
*
|
||||
* Retrieves the class structure of the immediate parent type of the
|
||||
* class passed in.
|
||||
*
|
||||
* This is a convenience function often needed in class initializers.
|
||||
* It returns the class structure of the immediate parent type of the
|
||||
* class passed in. Since derived classes hold a reference count on
|
||||
* their parent classes as long as they are instantiated, the returned
|
||||
* class will always exist.
|
||||
*
|
||||
* Since derived classes hold a reference on their parent classes as
|
||||
* long as they are instantiated, the returned class will always exist.
|
||||
*
|
||||
* This function is essentially equivalent to:
|
||||
* g_type_class_peek (g_type_parent (G_TYPE_FROM_CLASS (g_class)))
|
||||
*
|
||||
* Returns: (type GObject.TypeClass) (transfer none): the parent class
|
||||
* of @g_class
|
||||
* of @g_class
|
||||
*/
|
||||
gpointer
|
||||
g_type_class_peek_parent (gpointer g_class)
|
||||
@ -3207,9 +2948,9 @@ g_type_class_peek_parent (gpointer g_class)
|
||||
* Returns the #GTypeInterface structure of an interface to which the
|
||||
* passed in class conforms.
|
||||
*
|
||||
* Returns: (type GObject.TypeInterface) (transfer none): the #GTypeInterface
|
||||
* structure of @iface_type if implemented by @instance_class, %NULL
|
||||
* otherwise
|
||||
* Returns: (type GObject.TypeInterface) (transfer none) (nullable): the #GTypeInterface
|
||||
* structure of @iface_type if implemented by @instance_class, %NULL
|
||||
* otherwise
|
||||
*/
|
||||
gpointer
|
||||
g_type_interface_peek (gpointer instance_class,
|
||||
@ -3237,14 +2978,15 @@ g_type_interface_peek (gpointer instance_class,
|
||||
* @g_iface: (type GObject.TypeInterface): a #GTypeInterface structure
|
||||
*
|
||||
* Returns the corresponding #GTypeInterface structure of the parent type
|
||||
* of the instance type to which @g_iface belongs. This is useful when
|
||||
* deriving the implementation of an interface from the parent type and
|
||||
* then possibly overriding some methods.
|
||||
* of the instance type to which @g_iface belongs.
|
||||
*
|
||||
* Returns: (transfer none) (type GObject.TypeInterface): the
|
||||
* corresponding #GTypeInterface structure of the parent type of the
|
||||
* instance type to which @g_iface belongs, or %NULL if the parent
|
||||
* type doesn't conform to the interface
|
||||
* This is useful when deriving the implementation of an interface from the
|
||||
* parent type and then possibly overriding some methods.
|
||||
*
|
||||
* Returns: (transfer none) (type GObject.TypeInterface) (nullable): the
|
||||
* corresponding #GTypeInterface structure of the parent type of the
|
||||
* instance type to which @g_iface belongs, or %NULL if the parent
|
||||
* type doesn't conform to the interface
|
||||
*/
|
||||
gpointer
|
||||
g_type_interface_peek_parent (gpointer g_iface)
|
||||
@ -3285,12 +3027,43 @@ g_type_interface_peek_parent (gpointer g_iface)
|
||||
*
|
||||
* Since: 2.4
|
||||
*
|
||||
* Deprecated: 2.84: Use g_type_default_interface_get() instead
|
||||
*
|
||||
* Returns: (type GObject.TypeInterface) (transfer none): the default
|
||||
* vtable for the interface; call g_type_default_interface_unref()
|
||||
* when you are done using the interface.
|
||||
* vtable for the interface; call g_type_default_interface_unref()
|
||||
* when you are done using the interface.
|
||||
*/
|
||||
gpointer
|
||||
g_type_default_interface_ref (GType g_type)
|
||||
{
|
||||
return g_type_default_interface_get (g_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_type_default_interface_get:
|
||||
* @g_type: an interface type
|
||||
*
|
||||
* Returns the default interface vtable for the given @g_type.
|
||||
*
|
||||
* If the type is not currently in use, then the default vtable
|
||||
* for the type will be created and initialized by calling
|
||||
* the base interface init and default vtable init functions for
|
||||
* the type (the @base_init and @class_init members of #GTypeInfo).
|
||||
*
|
||||
* If you don't want to create the interface vtable, you should use
|
||||
* g_type_default_interface_peek() instead.
|
||||
*
|
||||
* Calling g_type_default_interface_get() is useful when you
|
||||
* want to make sure that signals and properties for an interface
|
||||
* have been installed.
|
||||
*
|
||||
* Returns: (type GObject.TypeInterface) (transfer none): the default
|
||||
* vtable for the interface.
|
||||
*
|
||||
* Since: 2.84
|
||||
*/
|
||||
gpointer
|
||||
g_type_default_interface_get (GType g_type)
|
||||
{
|
||||
TypeNode *node;
|
||||
gpointer dflt_vtable;
|
||||
@ -3298,8 +3071,7 @@ g_type_default_interface_ref (GType g_type)
|
||||
G_WRITE_LOCK (&type_rw_lock);
|
||||
|
||||
node = lookup_type_node_I (g_type);
|
||||
if (!node || !NODE_IS_IFACE (node) ||
|
||||
(node->data && NODE_REFCOUNT (node) == 0))
|
||||
if (!node || !NODE_IS_IFACE (node))
|
||||
{
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
g_critical ("cannot retrieve default vtable for invalid or non-interface type '%s'",
|
||||
@ -3317,8 +3089,6 @@ g_type_default_interface_ref (GType g_type)
|
||||
type_iface_ensure_dflt_vtable_Wm (node);
|
||||
g_rec_mutex_unlock (&class_init_rec_mutex);
|
||||
}
|
||||
else
|
||||
type_data_ref_Wm (node); /* ref_count >= 1 already */
|
||||
|
||||
dflt_vtable = node->data->iface.dflt_vtable;
|
||||
G_WRITE_UNLOCK (&type_rw_lock);
|
||||
@ -3336,8 +3106,8 @@ g_type_default_interface_ref (GType g_type)
|
||||
* Since: 2.4
|
||||
*
|
||||
* Returns: (type GObject.TypeInterface) (transfer none): the default
|
||||
* vtable for the interface, or %NULL if the type is not currently
|
||||
* in use
|
||||
* vtable for the interface, or %NULL if the type is not currently
|
||||
* in use
|
||||
*/
|
||||
gpointer
|
||||
g_type_default_interface_peek (GType g_type)
|
||||
@ -3346,7 +3116,7 @@ g_type_default_interface_peek (GType g_type)
|
||||
gpointer vtable;
|
||||
|
||||
node = lookup_type_node_I (g_type);
|
||||
if (node && NODE_IS_IFACE (node) && NODE_REFCOUNT (node))
|
||||
if (node && NODE_IS_IFACE (node) && node->data)
|
||||
vtable = node->data->iface.dflt_vtable;
|
||||
else
|
||||
vtable = NULL;
|
||||
@ -3360,38 +3130,33 @@ g_type_default_interface_peek (GType g_type)
|
||||
* structure for an interface, as returned by g_type_default_interface_ref()
|
||||
*
|
||||
* Decrements the reference count for the type corresponding to the
|
||||
* interface default vtable @g_iface. If the type is dynamic, then
|
||||
* when no one is using the interface and all references have
|
||||
* been released, the finalize function for the interface's default
|
||||
* vtable (the @class_finalize member of #GTypeInfo) will be called.
|
||||
* interface default vtable @g_iface.
|
||||
*
|
||||
* If the type is dynamic, then when no one is using the interface and all
|
||||
* references have been released, the finalize function for the interface's
|
||||
* default vtable (the @class_finalize member of #GTypeInfo) will be called.
|
||||
*
|
||||
* Since: 2.4
|
||||
*
|
||||
* Deprecated: 2.84: Interface reference counting has been removed and
|
||||
* interface types now cannot be finalized. This function no longer does
|
||||
* anything.
|
||||
*/
|
||||
void
|
||||
g_type_default_interface_unref (gpointer g_iface)
|
||||
{
|
||||
TypeNode *node;
|
||||
GTypeInterface *vtable = g_iface;
|
||||
|
||||
g_return_if_fail (g_iface != NULL);
|
||||
|
||||
node = lookup_type_node_I (vtable->g_type);
|
||||
if (node && NODE_IS_IFACE (node))
|
||||
type_data_unref_U (node, FALSE);
|
||||
else
|
||||
g_critical ("cannot unreference invalid interface default vtable for '%s'",
|
||||
type_descriptive_name_I (vtable->g_type));
|
||||
}
|
||||
|
||||
/**
|
||||
* g_type_name:
|
||||
* @type: type to return name for
|
||||
*
|
||||
* Get the unique name that is assigned to a type ID. Note that this
|
||||
* function (like all other GType API) cannot cope with invalid type
|
||||
* IDs. %G_TYPE_INVALID may be passed to this function, as may be any
|
||||
* other validly registered type ID, but randomized type IDs should
|
||||
* not be passed in and will most likely lead to a crash.
|
||||
* Get the unique name that is assigned to a type ID.
|
||||
*
|
||||
* Note that this function (like all other GType API) cannot cope with
|
||||
* invalid type IDs. %G_TYPE_INVALID may be passed to this function, as
|
||||
* may be any other validly registered type ID, but randomized type IDs
|
||||
* should not be passed in and will most likely lead to a crash.
|
||||
*
|
||||
* Returns: (nullable): static type name or %NULL
|
||||
*/
|
||||
@ -4288,7 +4053,7 @@ type_check_is_value_type_U (GType type)
|
||||
restart_check:
|
||||
if (node)
|
||||
{
|
||||
if (node->data && NODE_REFCOUNT (node) > 0 &&
|
||||
if (node->data &&
|
||||
node->data->common.value_table->value_init)
|
||||
tflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
|
||||
else if (NODE_IS_IFACE (node))
|
||||
@ -4343,25 +4108,26 @@ g_type_check_value_holds (const GValue *value,
|
||||
* that implements or has internal knowledge of the implementation of
|
||||
* @type.
|
||||
*
|
||||
* Returns: location of the #GTypeValueTable associated with @type or
|
||||
* %NULL if there is no #GTypeValueTable associated with @type
|
||||
* Returns: (nullable) (transfer none): location of the #GTypeValueTable
|
||||
* associated with @type or %NULL if there is no #GTypeValueTable
|
||||
* associated with @type
|
||||
*/
|
||||
GTypeValueTable*
|
||||
GTypeValueTable *
|
||||
g_type_value_table_peek (GType type)
|
||||
{
|
||||
GTypeValueTable *vtable = NULL;
|
||||
TypeNode *node = lookup_type_node_I (type);
|
||||
gboolean has_refed_data, has_table;
|
||||
gboolean has_data, has_table;
|
||||
|
||||
if (node && NODE_REFCOUNT (node) && node->mutatable_check_cache)
|
||||
if (node != NULL && node->mutatable_check_cache)
|
||||
return node->data->common.value_table;
|
||||
|
||||
G_READ_LOCK (&type_rw_lock);
|
||||
|
||||
restart_table_peek:
|
||||
has_refed_data = node && node->data && NODE_REFCOUNT (node) > 0;
|
||||
has_table = has_refed_data && node->data->common.value_table->value_init;
|
||||
if (has_refed_data)
|
||||
has_data = node != NULL && node->data != NULL;
|
||||
has_table = has_data && node->data->common.value_table->value_init;
|
||||
if (has_data)
|
||||
{
|
||||
if (has_table)
|
||||
vtable = node->data->common.value_table;
|
||||
@ -4391,7 +4157,7 @@ g_type_value_table_peek (GType type)
|
||||
|
||||
if (!node)
|
||||
g_critical (G_STRLOC ": type id '%" G_GUINTPTR_FORMAT "' is invalid", (guintptr) type);
|
||||
if (!has_refed_data)
|
||||
if (!has_data)
|
||||
g_critical ("can't peek value table for type '%s' which is not currently referenced",
|
||||
type_descriptive_name_I (type));
|
||||
|
||||
@ -5039,7 +4805,7 @@ g_type_class_get_private (GTypeClass *klass,
|
||||
if (NODE_PARENT_TYPE (private_node))
|
||||
{
|
||||
parent_node = lookup_type_node_I (NODE_PARENT_TYPE (private_node));
|
||||
g_assert (parent_node->data && NODE_REFCOUNT (parent_node) > 0);
|
||||
g_assert (parent_node->data);
|
||||
|
||||
if (G_UNLIKELY (private_node->data->class.class_private_size == parent_node->data->class.class_private_size))
|
||||
{
|
||||
|
@ -759,6 +759,8 @@ gboolean g_type_is_a (GType type,
|
||||
/* Hoist exact GType comparisons into the caller */
|
||||
#define g_type_is_a(a,b) ((a) == (b) || (g_type_is_a) ((a), (b)))
|
||||
|
||||
GOBJECT_AVAILABLE_IN_2_84
|
||||
gpointer g_type_class_get (GType type);
|
||||
GOBJECT_AVAILABLE_IN_ALL
|
||||
gpointer g_type_class_ref (GType type);
|
||||
GOBJECT_AVAILABLE_IN_ALL
|
||||
@ -775,6 +777,8 @@ gpointer g_type_interface_peek (gpointer instance_
|
||||
GOBJECT_AVAILABLE_IN_ALL
|
||||
gpointer g_type_interface_peek_parent (gpointer g_iface);
|
||||
|
||||
GOBJECT_AVAILABLE_IN_2_84
|
||||
gpointer g_type_default_interface_get (GType g_type);
|
||||
GOBJECT_AVAILABLE_IN_ALL
|
||||
gpointer g_type_default_interface_ref (GType g_type);
|
||||
GOBJECT_AVAILABLE_IN_ALL
|
||||
|
Loading…
x
Reference in New Issue
Block a user