mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
gobject: extract duplicate code for toggle reference in g_object_unref()
Move comment logic to one place. Add toggle_refs_check_and_ref_or_deref().
This commit is contained in:
parent
1bb5661198
commit
f17cfcf930
@ -3949,25 +3949,54 @@ typedef struct {
|
||||
} toggle_refs[1]; /* flexible array */
|
||||
} ToggleRefStack;
|
||||
|
||||
static GToggleNotify
|
||||
toggle_refs_get_notify_unlocked (GObject *object,
|
||||
gpointer *out_data)
|
||||
G_ALWAYS_INLINE static inline gboolean
|
||||
toggle_refs_check_and_ref_or_deref (GObject *object,
|
||||
gboolean is_ref,
|
||||
gint *old_ref,
|
||||
GToggleNotify *toggle_notify,
|
||||
gpointer *toggle_data)
|
||||
{
|
||||
ToggleRefStack *tstackptr;
|
||||
const gint ref_curr = is_ref ? 1 : 2;
|
||||
const gint ref_next = is_ref ? 2 : 1;
|
||||
gboolean success;
|
||||
|
||||
if (!OBJECT_HAS_TOGGLE_REF (object))
|
||||
return NULL;
|
||||
#if G_ENABLE_DEBUG
|
||||
g_assert (ref_curr == *old_ref);
|
||||
#endif
|
||||
|
||||
tstackptr = g_datalist_id_get_data (&object->qdata, quark_toggle_refs);
|
||||
*toggle_notify = NULL;
|
||||
*toggle_data = NULL;
|
||||
|
||||
if (tstackptr->n_toggle_refs != 1)
|
||||
object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS);
|
||||
|
||||
/* @old_ref is mainly an (out) parameter. On failure to compare-and-exchange,
|
||||
* we MUST return the new value which the caller will use for retry.*/
|
||||
|
||||
success = g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count,
|
||||
ref_curr,
|
||||
ref_next,
|
||||
old_ref);
|
||||
|
||||
if (success && OBJECT_HAS_TOGGLE_REF (object))
|
||||
{
|
||||
g_critical ("Unexpected number of toggle-refs. g_object_add_toggle_ref() must be paired with g_object_remove_toggle_ref()");
|
||||
return NULL;
|
||||
ToggleRefStack *tstackptr;
|
||||
|
||||
tstackptr = g_datalist_id_get_data (&object->qdata, quark_toggle_refs);
|
||||
|
||||
if (tstackptr->n_toggle_refs != 1)
|
||||
{
|
||||
g_critical ("Unexpected number of toggle-refs. g_object_add_toggle_ref() must be paired with g_object_remove_toggle_ref()");
|
||||
}
|
||||
else
|
||||
{
|
||||
*toggle_notify = tstackptr->toggle_refs[0].notify;
|
||||
*toggle_data = tstackptr->toggle_refs[0].data;
|
||||
}
|
||||
}
|
||||
|
||||
*out_data = tstackptr->toggle_refs[0].data;
|
||||
return tstackptr->toggle_refs[0].notify;
|
||||
object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4148,16 +4177,8 @@ retry:
|
||||
}
|
||||
else if (old_ref == 1)
|
||||
{
|
||||
gboolean do_retry;
|
||||
|
||||
/* With ref count 1, check whether we need to emit a toggle notification. */
|
||||
object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS);
|
||||
do_retry = !g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count,
|
||||
old_ref, old_ref + 1, &old_ref);
|
||||
if (!do_retry)
|
||||
toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data);
|
||||
object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS);
|
||||
if (do_retry)
|
||||
if (!toggle_refs_check_and_ref_or_deref (object, TRUE, &old_ref, &toggle_notify, &toggle_data))
|
||||
goto retry;
|
||||
}
|
||||
else
|
||||
@ -4282,7 +4303,6 @@ g_object_unref (gpointer _object)
|
||||
GToggleNotify toggle_notify;
|
||||
gpointer toggle_data;
|
||||
GObjectNotifyQueue *nqueue;
|
||||
gboolean do_retry;
|
||||
GType obj_gtype;
|
||||
|
||||
g_return_if_fail (G_IS_OBJECT (object));
|
||||
@ -4331,17 +4351,8 @@ retry_beginning:
|
||||
*
|
||||
* We need to take a lock, to avoid races. */
|
||||
|
||||
object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS);
|
||||
|
||||
if (!g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count,
|
||||
old_ref, old_ref - 1, &old_ref))
|
||||
{
|
||||
object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS);
|
||||
goto retry_beginning;
|
||||
}
|
||||
|
||||
toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data);
|
||||
object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS);
|
||||
if (!toggle_refs_check_and_ref_or_deref (object, FALSE, &old_ref, &toggle_notify, &toggle_data))
|
||||
goto retry_beginning;
|
||||
|
||||
/* Beware: object might be a dangling pointer. */
|
||||
TRACE (GOBJECT_OBJECT_UNREF (object, obj_gtype, old_ref));
|
||||
@ -4425,15 +4436,7 @@ retry_decrement:
|
||||
* notification. Take a lock and check for that.
|
||||
*
|
||||
* In that case, we need a lock to get the toggle notification. */
|
||||
object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS);
|
||||
do_retry = !g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count,
|
||||
old_ref, old_ref - 1,
|
||||
&old_ref);
|
||||
if (!do_retry)
|
||||
toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data);
|
||||
object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS);
|
||||
|
||||
if (do_retry)
|
||||
if (!toggle_refs_check_and_ref_or_deref (object, FALSE, &old_ref, &toggle_notify, &toggle_data))
|
||||
goto retry_decrement;
|
||||
|
||||
/* Beware: object might be a dangling pointer. */
|
||||
|
Loading…
Reference in New Issue
Block a user