Clear target when the target pad disappears

When the target pad disappears (because it was explicitly unlinked or the
element was removed/unreffed) make sure we receive a notify with the unlink
function on the proxy pad and clear the target. We use a simple flag to not do
this and cause deadlocks when the target was changed explicitly using the
ghostpad functions.

Update the unit test because we now unref the target sooner (and correctly).
This commit is contained in:
Wim Taymans 2009-02-16 12:58:34 +01:00
parent 8efaf40013
commit 26f368f7e7
2 changed files with 81 additions and 6 deletions

View file

@ -56,6 +56,7 @@
#define GST_PROXY_PAD_PRIVATE(obj) (GST_PROXY_PAD_CAST (obj)->priv)
#define GST_PROXY_PAD_TARGET(pad) (GST_PROXY_PAD_PRIVATE (pad)->target)
#define GST_PROXY_PAD_INTERNAL(pad) (GST_PROXY_PAD_PRIVATE (pad)->internal)
#define GST_PROXY_PAD_RETARGET(pad) (GST_PROXY_PAD_PRIVATE (pad)->retarget)
#define GST_PROXY_GET_LOCK(pad) (GST_PROXY_PAD_PRIVATE (pad)->proxy_lock)
#define GST_PROXY_LOCK(pad) (g_mutex_lock (GST_PROXY_GET_LOCK (pad)))
#define GST_PROXY_UNLOCK(pad) (g_mutex_unlock (GST_PROXY_GET_LOCK (pad)))
@ -66,6 +67,7 @@ struct _GstProxyPadPrivate
GMutex *proxy_lock;
GstPad *target;
GstPad *internal;
gboolean retarget;
};
G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
@ -371,6 +373,24 @@ gst_proxy_pad_get_target (GstPad * pad)
return target;
}
static void
gst_proxy_pad_do_unlink (GstPad * pad)
{
GstPad *internal;
/* don't do anything if this unlink resulted from retargeting the pad
* controlled by the ghostpad. We only want to invalidate the target pad when
* the element suddently unlinked with our internal pad. */
if (GST_PROXY_PAD_RETARGET (pad))
return;
internal = GST_PROXY_PAD_INTERNAL (pad);
GST_DEBUG_OBJECT (pad, "pad is unlinked");
gst_proxy_pad_set_target (internal, NULL);
}
static void
gst_proxy_pad_dispose (GObject * object)
{
@ -426,6 +446,8 @@ gst_proxy_pad_init (GstProxyPad * ppad)
GST_DEBUG_FUNCPTR (gst_proxy_pad_do_fixatecaps));
gst_pad_set_setcaps_function (pad,
GST_DEBUG_FUNCPTR (gst_proxy_pad_do_setcaps));
gst_pad_set_unlink_function (pad,
GST_DEBUG_FUNCPTR (gst_proxy_pad_do_unlink));
}
#ifndef GST_DISABLE_LOADSAVE
@ -1119,11 +1141,15 @@ gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
(gpointer) on_src_target_notify, gpad);
}
GST_PROXY_PAD_RETARGET (internal) = TRUE;
/* unlink internal pad */
if (GST_PAD_IS_SRC (internal))
gst_pad_unlink (internal, oldtarget);
else
gst_pad_unlink (oldtarget, internal);
GST_PROXY_PAD_RETARGET (internal) = FALSE;
}
result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);

View file

@ -148,6 +148,8 @@ GST_START_TEST (test_remove2)
GST_END_TEST;
/* test if a ghost pad without a target can be linked and
* unlinked. An untargeted ghostpad has a default ANY caps unless there
* is a padtemplate that says something else.
@ -214,6 +216,46 @@ GST_START_TEST (test_ghost_pads_notarget)
GST_END_TEST;
/* Test that removing the target of a ghostpad properly sets the target of the
* ghostpad to NULL */
GST_START_TEST (test_remove_target)
{
GstElement *b1, *b2, *src, *sink;
GstPad *sinkpad, *ghost, *target;
b1 = gst_element_factory_make ("pipeline", NULL);
b2 = gst_element_factory_make ("bin", NULL);
src = gst_element_factory_make ("fakesrc", NULL);
sink = gst_element_factory_make ("fakesink", NULL);
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
fail_unless (gst_bin_add (GST_BIN (b2), sink));
fail_unless (gst_bin_add (GST_BIN (b1), src));
fail_unless (gst_bin_add (GST_BIN (b1), b2));
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
sinkpad = gst_element_get_static_pad (sink, "sink");
gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
ghost = gst_element_get_static_pad (b2, "sink");
target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
fail_unless (target == sinkpad);
gst_object_unref (target);
gst_object_unref (sinkpad);
gst_bin_remove (GST_BIN (b2), sink);
target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
fail_unless (target == NULL);
gst_object_unref (b1);
}
GST_END_TEST;
/* test if linking fails over different bins using a pipeline
* like this:
*
@ -357,9 +399,9 @@ GST_START_TEST (test_ghost_pads)
ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2); /* gsink */
ASSERT_OBJECT_REFCOUNT (isink, "isink", 2); /* gsink */
ASSERT_OBJECT_REFCOUNT (isink, "isink", 1); /* gsink */
ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* gsrc */
ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 2); /* gsrc */
ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1); /* gsrc */
gst_object_unref (gsink);
ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);
@ -763,6 +805,7 @@ GST_START_TEST (test_ghost_pads_forward_setcaps)
gst_object_unref (src_template);
gst_object_unref (sink_template);
}
GST_END_TEST;
static gint linked_count1;
@ -771,26 +814,29 @@ static gint linked_count2;
static gint unlinked_count2;
static GstPadLinkReturn
pad_linked1 (GstPad *pad, GstPad *peer)
pad_linked1 (GstPad * pad, GstPad * peer)
{
linked_count1++;
return GST_PAD_LINK_OK;
}
static void
pad_unlinked1 (GstPad *pad)
pad_unlinked1 (GstPad * pad)
{
unlinked_count1++;
}
static GstPadLinkReturn
pad_linked2 (GstPad *pad, GstPad *peer)
pad_linked2 (GstPad * pad, GstPad * peer)
{
linked_count2++;
return GST_PAD_LINK_OK;
}
static void
pad_unlinked2 (GstPad *pad)
pad_unlinked2 (GstPad * pad)
{
unlinked_count2++;
}
@ -863,6 +909,7 @@ GST_START_TEST (test_ghost_pads_sink_link_unlink)
gst_object_unref (srctempl);
gst_object_unref (sinktempl);
}
GST_END_TEST;
GST_START_TEST (test_ghost_pads_src_link_unlink)
@ -965,6 +1012,7 @@ GST_START_TEST (test_ghost_pads_src_link_unlink)
gst_object_unref (srctempl);
gst_object_unref (sinktempl);
}
GST_END_TEST;
static Suite *
@ -977,6 +1025,7 @@ gst_ghost_pad_suite (void)
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_remove1);
tcase_add_test (tc_chain, test_remove2);
tcase_add_test (tc_chain, test_remove_target);
tcase_add_test (tc_chain, test_link);
tcase_add_test (tc_chain, test_ghost_pads);
tcase_add_test (tc_chain, test_ghost_pads_bin);