Merge branch 'ebassi/gtype-refcount' into 'main'

Drop TypeNode reference counting

See merge request GNOME/glib!3255
This commit is contained in:
Philip Withnall 2025-02-03 14:38:24 +00:00
commit cac9100960
2 changed files with 171 additions and 401 deletions

View File

@ -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))
{

View File

@ -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