gstpad: Recheck pads when linking after temporary unlock

This commit makes sure that pads are valid for linking
after the pads has been temporarily unlocked in the linking process.
Not doing this opens up for a race condition where
pads potentially can be linked twice.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5678>
This commit is contained in:
Daniel Moberg 2023-11-15 10:03:52 +00:00 committed by Tim-Philipp Müller
parent 15e9b513da
commit 1eca0a1049

View file

@ -2378,22 +2378,18 @@ wrong_grandparents:
}
}
/* FIXME leftover from an attempt at refactoring... */
/* call with the two pads unlocked, when this function returns GST_PAD_LINK_OK,
* the two pads will be locked in the srcpad, sinkpad order. */
/* check that pads does not have any exisiting links
* and that hierarchy is valid for linking.
*
* The LOCK should be held on both pads
*/
static GstPadLinkReturn
gst_pad_link_prepare (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
gst_pad_link_check_relations (GstPad * srcpad, GstPad * sinkpad,
GstPadLinkCheck flags)
{
GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
GST_OBJECT_LOCK (srcpad);
if (G_UNLIKELY (GST_PAD_PEER (srcpad) != NULL))
goto src_was_linked;
GST_OBJECT_LOCK (sinkpad);
if (G_UNLIKELY (GST_PAD_PEER (sinkpad) != NULL))
goto sink_was_linked;
@ -2403,12 +2399,6 @@ gst_pad_link_prepare (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
&& !gst_pad_link_check_hierarchy (srcpad, sinkpad))
goto wrong_hierarchy;
/* check pad caps for non-empty intersection */
if (!gst_pad_link_check_compatible_unlocked (srcpad, sinkpad, flags))
goto no_format;
/* FIXME check pad scheduling for non-empty intersection */
return GST_PAD_LINK_OK;
src_was_linked:
@ -2418,7 +2408,6 @@ src_was_linked:
GST_DEBUG_PAD_NAME (GST_PAD_PEER (srcpad)));
/* we do not emit a warning in this case because unlinking cannot
* be made MT safe.*/
GST_OBJECT_UNLOCK (srcpad);
return GST_PAD_LINK_WAS_LINKED;
}
sink_was_linked:
@ -2428,23 +2417,57 @@ sink_was_linked:
GST_DEBUG_PAD_NAME (GST_PAD_PEER (sinkpad)));
/* we do not emit a warning in this case because unlinking cannot
* be made MT safe.*/
GST_OBJECT_UNLOCK (sinkpad);
GST_OBJECT_UNLOCK (srcpad);
return GST_PAD_LINK_WAS_LINKED;
}
wrong_hierarchy:
{
GST_CAT_INFO (GST_CAT_PADS, "pads have wrong hierarchy");
GST_OBJECT_UNLOCK (sinkpad);
GST_OBJECT_UNLOCK (srcpad);
return GST_PAD_LINK_WRONG_HIERARCHY;
}
no_format:
{
}
/* FIXME leftover from an attempt at refactoring... */
/* call with the two pads unlocked, when this function returns GST_PAD_LINK_OK,
* the two pads will be locked in the srcpad, sinkpad order. */
static GstPadLinkReturn
gst_pad_link_prepare (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
{
GstPadLinkReturn result;
GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
GST_OBJECT_LOCK (srcpad);
GST_OBJECT_LOCK (sinkpad);
/* Check pads state, not already linked and correct hierachy. */
result = gst_pad_link_check_relations (srcpad, sinkpad, flags);
if (result != GST_PAD_LINK_OK)
goto unlock_and_return;
/* check pad caps for non-empty intersection */
if (!gst_pad_link_check_compatible_unlocked (srcpad, sinkpad, flags)) {
GST_CAT_INFO (GST_CAT_PADS, "caps are incompatible");
result = GST_PAD_LINK_NOFORMAT;
goto unlock_and_return;
}
/* Need to recheck our pads since gst_pad_link_check_compatible_unlocked might have temporarily unlocked them.
Keeping the first check, because gst_pad_link_check_compatible_unlocked potentially is an expensive operation
which gst_pad_link_check_relations is not. */
result = gst_pad_link_check_relations (srcpad, sinkpad, flags);
if (result != GST_PAD_LINK_OK)
goto unlock_and_return;
/* FIXME check pad scheduling for non-empty intersection */
return GST_PAD_LINK_OK;
unlock_and_return:
{
GST_OBJECT_UNLOCK (sinkpad);
GST_OBJECT_UNLOCK (srcpad);
return GST_PAD_LINK_NOFORMAT;
return result;
}
}