signals: Ensure we ref handler in emission fast path

We need to keep a reference to the handler in the fast path, just like
in the slow path, otherwise if another thread disconnects the handler
we may destroy the closure while we're using it without the lock held.

We also move the freeing of the instance to after the emission is totally
done as the handler_unref_R (and the tracepoint) reference it.

https://bugzilla.gnome.org/show_bug.cgi?id=694253
This commit is contained in:
Alexander Larsson 2013-02-21 16:10:36 +01:00
parent 3e274423ba
commit aede774642

View File

@ -3127,6 +3127,7 @@ g_signal_emit_valist (gpointer instance,
)
{
HandlerList* hlist = handler_list_lookup (node->signal_id, instance);
Handler *fastpath_handler = NULL;
Handler *l;
GClosure *closure = NULL;
gboolean fastpath = TRUE;
@ -3159,6 +3160,7 @@ g_signal_emit_valist (gpointer instance,
}
else
{
fastpath_handler = l;
closure = l->closure;
if (l->after)
run_type = G_SIGNAL_RUN_LAST;
@ -3207,6 +3209,9 @@ g_signal_emit_valist (gpointer instance,
emission.chain_type = instance_type;
emission_push (&g_recursive_emissions, &emission);
if (fastpath_handler)
handler_ref (fastpath_handler);
SIGNAL_UNLOCK ();
TRACE(GOBJECT_SIGNAL_EMIT(signal_id, detail, instance, instance_type));
@ -3227,7 +3232,6 @@ g_signal_emit_valist (gpointer instance,
node->n_params,
node->param_types);
accumulate (&emission.ihint, &emission_return, &accu, accumulator);
g_object_unref (instance);
}
SIGNAL_LOCK ();
@ -3235,6 +3239,9 @@ g_signal_emit_valist (gpointer instance,
emission.chain_type = G_TYPE_NONE;
emission_pop (&g_recursive_emissions, &emission);
if (fastpath_handler)
handler_unref_R (signal_id, instance, fastpath_handler);
SIGNAL_UNLOCK ();
if (accumulator)
@ -3267,6 +3274,9 @@ g_signal_emit_valist (gpointer instance,
TRACE(GOBJECT_SIGNAL_EMIT_END(signal_id, detail, instance, instance_type));
if (closure != NULL)
g_object_unref (instance);
return;
}
}