gst/gstpad.c: Use thread-safe internal links iterator. Fixes #549504.

Original commit message from CVS:
Patch by: Olivier Crete <tester at tester dot ca>
* gst/gstpad.c: (gst_pad_iterate_internal_links_default),
(gst_pad_event_default_dispatch), (gst_pad_dispatcher):
Use thread-safe internal links iterator. Fixes #549504.
This commit is contained in:
Olivier Crete 2008-09-01 11:27:45 +00:00 committed by Wim Taymans
parent 68037404b8
commit 390369246e
2 changed files with 122 additions and 53 deletions

View file

@ -1,3 +1,11 @@
2008-09-01 Wim Taymans <wim.taymans@collabora.co.uk>
Patch by: Olivier Crete <tester at tester dot ca>
* gst/gstpad.c: (gst_pad_iterate_internal_links_default),
(gst_pad_event_default_dispatch), (gst_pad_dispatcher):
Use thread-safe internal links iterator. Fixes #549504.
2008-09-01 Wim Taymans <wim.taymans@collabora.co.uk> 2008-09-01 Wim Taymans <wim.taymans@collabora.co.uk>
Based on patch by: Olivier Crete <tester at tester dot ca> Based on patch by: Olivier Crete <tester at tester dot ca>

View file

@ -2962,9 +2962,9 @@ GstIterator *
gst_pad_iterate_internal_links_default (GstPad * pad) gst_pad_iterate_internal_links_default (GstPad * pad)
{ {
GstIterator *res; GstIterator *res;
GstElement *parent = NULL;
GList **padlist; GList **padlist;
guint32 *cookie; guint32 *cookie;
GMutex *lock;
gpointer owner; gpointer owner;
GstIteratorDisposeFunction dispose; GstIteratorDisposeFunction dispose;
@ -2995,9 +2995,13 @@ gst_pad_iterate_internal_links_default (GstPad * pad)
padlist = &data->list; padlist = &data->list;
owner = data; owner = data;
dispose = (GstIteratorDisposeFunction) int_link_iter_data_free; dispose = (GstIteratorDisposeFunction) int_link_iter_data_free;
/* reuse the pad lock, it's all we have here */
lock = GST_OBJECT_GET_LOCK (pad);
} else } else
#endif #endif
{ {
GstElement *parent;
GST_OBJECT_LOCK (pad); GST_OBJECT_LOCK (pad);
parent = GST_PAD_PARENT (pad); parent = GST_PAD_PARENT (pad);
if (!parent || !GST_IS_ELEMENT (parent)) if (!parent || !GST_IS_ELEMENT (parent))
@ -3016,11 +3020,12 @@ gst_pad_iterate_internal_links_default (GstPad * pad)
cookie = &parent->pads_cookie; cookie = &parent->pads_cookie;
owner = parent; owner = parent;
dispose = (GstIteratorDisposeFunction) gst_object_unref; dispose = (GstIteratorDisposeFunction) gst_object_unref;
lock = GST_OBJECT_GET_LOCK (parent);
} }
res = gst_iterator_new_list (GST_TYPE_PAD, res = gst_iterator_new_list (GST_TYPE_PAD,
GST_OBJECT_GET_LOCK (parent), lock, cookie, padlist, owner, (GstIteratorItemFunction) iterate_pad,
cookie, padlist, owner, (GstIteratorItemFunction) iterate_pad, dispose); dispose);
return res; return res;
@ -3156,52 +3161,86 @@ gst_pad_get_internal_links (GstPad * pad)
static gboolean static gboolean
gst_pad_event_default_dispatch (GstPad * pad, GstEvent * event) gst_pad_event_default_dispatch (GstPad * pad, GstEvent * event)
{ {
GList *orig, *pads; gboolean result = FALSE;
gboolean result; GstIterator *iter;
gboolean done = FALSE;
gpointer item;
GstPad *eventpad;
GList *pushed_pads = NULL;
GST_INFO_OBJECT (pad, "Sending event %p (%s) to all internally linked pads", GST_INFO_OBJECT (pad, "Sending event %p (%s) to all internally linked pads",
event, GST_EVENT_TYPE_NAME (event)); event, GST_EVENT_TYPE_NAME (event));
orig = pads = gst_pad_get_internal_links (pad); iter = gst_pad_iterate_internal_links (pad);
if (!pads) { if (!iter)
/* If this is a sinkpad and we don't have pads to send the event to, we goto no_iter;
* return TRUE. This is so that when using the default handler on a sink
* element, we don't fail to push it. */
result = (GST_PAD_DIRECTION (pad) == GST_PAD_SINK);
} else {
/* we have pads, the result will be TRUE if one of the pads handled the
* event in the code below. */
result = FALSE;
}
while (pads) { while (!done) {
GstPad *eventpad = GST_PAD_CAST (pads->data); switch (gst_iterator_next (iter, &item)) {
case GST_ITERATOR_OK:
eventpad = GST_PAD (item);
pads = g_list_next (pads); /* if already pushed, skip */
if (g_list_find (pushed_pads, eventpad)) {
gst_object_unref (item);
break;
}
if (GST_PAD_DIRECTION (eventpad) == GST_PAD_SRC) { if (GST_PAD_DIRECTION (eventpad) == GST_PAD_SRC) {
/* for each pad we send to, we should ref the event; it's up /* for each pad we send to, we should ref the event; it's up
* to downstream to unref again when handled. */ * to downstream to unref again when handled. */
GST_LOG_OBJECT (pad, "Reffing and sending event %p (%s) to %s:%s", GST_LOG_OBJECT (pad, "Reffing and sending event %p (%s) to %s:%s",
event, GST_EVENT_TYPE_NAME (event), GST_DEBUG_PAD_NAME (eventpad)); event, GST_EVENT_TYPE_NAME (event),
gst_event_ref (event); GST_DEBUG_PAD_NAME (eventpad));
result |= gst_pad_push_event (eventpad, event); gst_event_ref (event);
} else { result |= gst_pad_push_event (eventpad, event);
/* we only send the event on one pad, multi-sinkpad elements } else {
* should implement a handler */ /* we only send the event on one pad, multi-sinkpad elements
GST_LOG_OBJECT (pad, "sending event %p (%s) to one sink pad %s:%s", * should implement a handler */
event, GST_EVENT_TYPE_NAME (event), GST_DEBUG_PAD_NAME (eventpad)); GST_LOG_OBJECT (pad, "sending event %p (%s) to one sink pad %s:%s",
result = gst_pad_push_event (eventpad, event); event, GST_EVENT_TYPE_NAME (event),
goto done; GST_DEBUG_PAD_NAME (eventpad));
result = gst_pad_push_event (eventpad, event);
done = TRUE;
event = NULL;
}
pushed_pads = g_list_prepend (pushed_pads, eventpad);
gst_object_unref (item);
break;
case GST_ITERATOR_RESYNC:
/* FIXME, if we want to reset the result value we need to remember which
* pads pushed with which result */
gst_iterator_resync (iter);
break;
case GST_ITERATOR_ERROR:
GST_ERROR_OBJECT (pad, "Could not iterate over internally linked pads");
done = TRUE;
break;
case GST_ITERATOR_DONE:
done = TRUE;
break;
} }
} }
/* we handled the incoming event so we unref once */ gst_iterator_free (iter);
GST_LOG_OBJECT (pad, "handled event %p, unreffing", event);
gst_event_unref (event);
done: no_iter:
g_list_free (orig);
/* If this is a sinkpad and we don't have pads to send the event to, we
* return TRUE. This is so that when using the default handler on a sink
* element, we don't fail to push it. */
if (!pushed_pads)
result = (GST_PAD_DIRECTION (pad) == GST_PAD_SINK);
g_list_free (pushed_pads);
/* we handled the incoming event so we unref once */
if (event) {
GST_LOG_OBJECT (pad, "handled event %p, unreffing", event);
gst_event_unref (event);
}
return result; return result;
} }
@ -3257,32 +3296,54 @@ gst_pad_dispatcher (GstPad * pad, GstPadDispatcherFunction dispatch,
gpointer data) gpointer data)
{ {
gboolean res = FALSE; gboolean res = FALSE;
GList *int_pads, *orig; GstIterator *iter = NULL;
gboolean done = FALSE;
gpointer item;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE); g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (dispatch != NULL, FALSE); g_return_val_if_fail (dispatch != NULL, FALSE);
orig = int_pads = gst_pad_get_internal_links (pad); iter = gst_pad_iterate_internal_links (pad);
while (int_pads) { if (!iter)
GstPad *int_pad = GST_PAD_CAST (int_pads->data); goto no_iter;
GstPad *int_peer = gst_pad_get_peer (int_pad);
if (int_peer) { while (!done) {
GST_DEBUG_OBJECT (int_pad, "dispatching to peer %s:%s", switch (gst_iterator_next (iter, &item)) {
GST_DEBUG_PAD_NAME (int_peer)); case GST_ITERATOR_OK:
res = dispatch (int_peer, data); {
gst_object_unref (int_peer); GstPad *int_pad = GST_PAD_CAST (item);
if (res) GstPad *int_peer = gst_pad_get_peer (int_pad);
if (int_peer) {
GST_DEBUG_OBJECT (int_pad, "dispatching to peer %s:%s",
GST_DEBUG_PAD_NAME (int_peer));
done = res = dispatch (int_peer, data);
gst_object_unref (int_peer);
} else {
GST_DEBUG_OBJECT (int_pad, "no peer");
}
}
gst_object_unref (item);
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (iter);
break;
case GST_ITERATOR_ERROR:
done = TRUE;
GST_ERROR_OBJECT (pad, "Could not iterate internally linked pads");
break;
case GST_ITERATOR_DONE:
done = TRUE;
break; break;
} else {
GST_DEBUG_OBJECT (int_pad, "no peer");
} }
int_pads = g_list_next (int_pads);
} }
g_list_free (orig); gst_iterator_free (iter);
GST_DEBUG_OBJECT (pad, "done, result %d", res); GST_DEBUG_OBJECT (pad, "done, result %d", res);
no_iter:
return res; return res;
} }