gstelement: protect async state changes against spurious wake ups
When a pipeline is pre-rolling, it waits for all sink elements to report they have received a buffer before completing the transition to paused. This async wait is done using a state condition variable. The way this waits are currently implemented do not protect against spurious conditional wake ups, which may happen due to external factors in the kernel. This change implements the wait within a loop that iterates over the protected variable to reinitiates the wait if the wakeup was spurious. More details in the [GCond docs](https://docs.gtk.org/glib/struct.Cond.html). Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4086>
This commit is contained in:
parent
6ce4a12f0b
commit
53c145a158
@ -2500,11 +2500,19 @@ gst_element_get_state_func (GstElement * element,
|
|||||||
{
|
{
|
||||||
GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
|
GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
|
||||||
GstState old_pending;
|
GstState old_pending;
|
||||||
|
gint64 end_time;
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "getting state, timeout %"
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "getting state, timeout %"
|
||||||
GST_TIME_FORMAT, GST_TIME_ARGS (timeout));
|
GST_TIME_FORMAT, GST_TIME_ARGS (timeout));
|
||||||
|
|
||||||
GST_OBJECT_LOCK (element);
|
GST_OBJECT_LOCK (element);
|
||||||
|
|
||||||
|
if (timeout != GST_CLOCK_TIME_NONE) {
|
||||||
|
/* make timeout absolute */
|
||||||
|
end_time = g_get_monotonic_time () + (timeout / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
ret = GST_STATE_RETURN (element);
|
ret = GST_STATE_RETURN (element);
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s",
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s",
|
||||||
gst_element_state_change_return_get_name (ret));
|
gst_element_state_change_return_get_name (ret));
|
||||||
@ -2523,7 +2531,7 @@ gst_element_get_state_func (GstElement * element,
|
|||||||
|
|
||||||
old_pending = GST_STATE_PENDING (element);
|
old_pending = GST_STATE_PENDING (element);
|
||||||
if (old_pending != GST_STATE_VOID_PENDING) {
|
if (old_pending != GST_STATE_VOID_PENDING) {
|
||||||
gboolean signaled;
|
gboolean signaled = TRUE;
|
||||||
guint32 cookie;
|
guint32 cookie;
|
||||||
|
|
||||||
/* get cookie to detect state changes during waiting */
|
/* get cookie to detect state changes during waiting */
|
||||||
@ -2532,11 +2540,9 @@ gst_element_get_state_func (GstElement * element,
|
|||||||
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
|
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
|
||||||
"waiting for element to commit state");
|
"waiting for element to commit state");
|
||||||
|
|
||||||
/* we have a pending state change, wait for it to complete */
|
/* we have a pending state change, wait for it to complete or for
|
||||||
|
an interruption */
|
||||||
if (timeout != GST_CLOCK_TIME_NONE) {
|
if (timeout != GST_CLOCK_TIME_NONE) {
|
||||||
gint64 end_time;
|
|
||||||
/* make timeout absolute */
|
|
||||||
end_time = g_get_monotonic_time () + (timeout / 1000);
|
|
||||||
signaled = GST_STATE_WAIT_UNTIL (element, end_time);
|
signaled = GST_STATE_WAIT_UNTIL (element, end_time);
|
||||||
} else {
|
} else {
|
||||||
GST_STATE_WAIT (element);
|
GST_STATE_WAIT (element);
|
||||||
@ -2547,6 +2553,7 @@ gst_element_get_state_func (GstElement * element,
|
|||||||
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "timed out");
|
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "timed out");
|
||||||
/* timeout triggered */
|
/* timeout triggered */
|
||||||
ret = GST_STATE_CHANGE_ASYNC;
|
ret = GST_STATE_CHANGE_ASYNC;
|
||||||
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
if (cookie != element->state_cookie)
|
if (cookie != element->state_cookie)
|
||||||
goto interrupted;
|
goto interrupted;
|
||||||
@ -2566,6 +2573,7 @@ gst_element_get_state_func (GstElement * element,
|
|||||||
ret = GST_STATE_CHANGE_SUCCESS;
|
ret = GST_STATE_CHANGE_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} while (old_pending != GST_STATE (element));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (state)
|
if (state)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user