object: use weakref when advancing current transition

Fixes reference count leak when activating an object and transition fails
This commit is contained in:
Julian Bouzas
2021-06-01 13:46:52 -04:00
parent efb0f83d1f
commit 8698d4f43a

View File

@@ -143,6 +143,7 @@ struct _WpObjectPrivate
WpObjectFeatures ft_active;
GQueue *transitions; // element-type: WpFeatureActivationTransition*
GSource *idle_advnc_source;
GWeakRef ongoing_transition;
};
enum {
@@ -161,6 +162,7 @@ wp_object_init (WpObject * self)
g_weak_ref_init (&priv->core, NULL);
priv->transitions = g_queue_new ();
g_weak_ref_init (&priv->ongoing_transition, NULL);
}
static void
@@ -189,6 +191,7 @@ wp_object_finalize (GObject * object)
g_warn_if_fail (g_queue_is_empty (priv->transitions));
g_clear_pointer (&priv->transitions, g_queue_free);
g_clear_pointer (&priv->idle_advnc_source, g_source_unref);
g_weak_ref_clear (&priv->ongoing_transition);
g_weak_ref_clear (&priv->core);
/* everything must have been deactivated in dispose() */
@@ -309,17 +312,24 @@ static gboolean
wp_object_advance_transitions (WpObject * self)
{
WpObjectPrivate *priv = wp_object_get_instance_private (self);
WpTransition *t;
/* clear before advancing; a transition may need to schedule
a new call to wp_object_advance_transitions() */
g_clear_pointer (&priv->idle_advnc_source, g_source_unref);
while ((t = g_queue_peek_head (priv->transitions))) {
wp_transition_advance (t);
if (!wp_transition_get_completed (t))
while (TRUE) {
g_autoptr (WpTransition) t = g_weak_ref_get (&priv->ongoing_transition);
if (t) {
wp_transition_advance (t);
if (!wp_transition_get_completed (t))
break;
}
if (g_queue_is_empty (priv->transitions))
break;
g_object_unref (g_queue_pop_head (priv->transitions));
g_weak_ref_set (&priv->ongoing_transition,
g_queue_pop_head (priv->transitions));
}
return G_SOURCE_REMOVE;
@@ -382,7 +392,7 @@ wp_object_activate_closure (WpObject * self,
wp_transition_set_source_tag (transition, wp_object_activate);
wp_transition_set_data (transition, GUINT_TO_POINTER (features), NULL);
g_queue_push_tail (priv->transitions, g_object_ref (transition));
g_queue_push_tail (priv->transitions, transition);
if (!priv->idle_advnc_source) {
wp_core_idle_add (core, &priv->idle_advnc_source,
@@ -454,6 +464,7 @@ wp_object_update_features (WpObject * self, WpObjectFeatures activated,
WpObjectPrivate *priv = wp_object_get_instance_private (self);
guint old_ft = priv->ft_active;
g_autoptr (WpTransition) t = NULL;
priv->ft_active |= activated;
priv->ft_active &= ~deactivated;
@@ -464,7 +475,8 @@ wp_object_update_features (WpObject * self, WpObjectFeatures activated,
g_object_notify (G_OBJECT (self), "active-features");
}
if (!g_queue_is_empty (priv->transitions) && !priv->idle_advnc_source) {
t = g_weak_ref_get (&priv->ongoing_transition);
if ((t || !g_queue_is_empty (priv->transitions)) && !priv->idle_advnc_source) {
g_autoptr (WpCore) core = g_weak_ref_get (&priv->core);
g_return_if_fail (core != NULL);