sctpenc: Fix potential shutdown deadlock
authorJohan Sternerup <johast@axis.com>
Wed, 10 May 2023 10:00:15 +0000 (12:00 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Mon, 15 May 2023 09:20:32 +0000 (09:20 +0000)
When transitioning from state PAUSED to READY, the sctpenc element
could previously be stuck in an endless loop trying to resend data
in case the underlying sctp stream was in the process of
resetting. usrsctp_sendv() would repeatedly return EAGAIN with the
result that 0 bytes were sent and then sctpenc would retry forever.

To bring sctpenc out of the resend loop we just need to inform the
sink pad that it is flushing, which is already done for the associated
data queue, but we also need to set the bools associated with the
sinkpads that are used as the loop criterion.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4636>

subprojects/gst-plugins-bad/ext/sctp/gstsctpenc.c

index 3d94068..2fcbece 100644 (file)
@@ -331,6 +331,34 @@ gst_sctp_enc_get_property (GObject * object, guint prop_id, GValue * value,
   }
 }
 
+static void
+flush_sinkpad (const GValue * item, gpointer user_data)
+{
+  GstSctpEncPad *sctpenc_pad = g_value_get_object (item);
+  gboolean flush = GPOINTER_TO_INT (user_data);
+
+  if (flush) {
+    g_mutex_lock (&sctpenc_pad->lock);
+    sctpenc_pad->flushing = TRUE;
+    g_cond_signal (&sctpenc_pad->cond);
+    g_mutex_unlock (&sctpenc_pad->lock);
+  } else {
+    sctpenc_pad->flushing = FALSE;
+  }
+}
+
+static void
+flush_sinkpads (GstSctpEnc * self, gboolean state)
+{
+  GstIterator *it;
+
+  it = gst_element_iterate_sink_pads (GST_ELEMENT (self));
+  while (gst_iterator_foreach (it, flush_sinkpad,
+          GINT_TO_POINTER (state)) == GST_ITERATOR_RESYNC)
+    gst_iterator_resync (it);
+  gst_iterator_free (it);
+}
+
 static GstStateChangeReturn
 gst_sctp_enc_change_state (GstElement * element, GstStateChange transition)
 {
@@ -351,6 +379,7 @@ gst_sctp_enc_change_state (GstElement * element, GstStateChange transition)
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       stop_srcpad_task (self->src_pad, self);
+      flush_sinkpads (self, TRUE);
       self->src_ret = GST_FLOW_FLUSHING;
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
@@ -764,22 +793,6 @@ gst_sctp_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
   return ret;
 }
 
-static void
-flush_sinkpad (const GValue * item, gpointer user_data)
-{
-  GstSctpEncPad *sctpenc_pad = g_value_get_object (item);
-  gboolean flush = GPOINTER_TO_INT (user_data);
-
-  if (flush) {
-    g_mutex_lock (&sctpenc_pad->lock);
-    sctpenc_pad->flushing = TRUE;
-    g_cond_signal (&sctpenc_pad->cond);
-    g_mutex_unlock (&sctpenc_pad->lock);
-  } else {
-    sctpenc_pad->flushing = FALSE;
-  }
-}
-
 static gboolean
 gst_sctp_enc_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
 {
@@ -788,29 +801,17 @@ gst_sctp_enc_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_START:{
-      GstIterator *it;
-
       gst_data_queue_set_flushing (self->outbound_sctp_packet_queue, TRUE);
       gst_data_queue_flush (self->outbound_sctp_packet_queue);
 
-      it = gst_element_iterate_sink_pads (GST_ELEMENT (self));
-      while (gst_iterator_foreach (it, flush_sinkpad,
-              GINT_TO_POINTER (TRUE)) == GST_ITERATOR_RESYNC)
-        gst_iterator_resync (it);
-      gst_iterator_free (it);
+      flush_sinkpads (self, TRUE);
 
       ret = gst_pad_event_default (pad, parent, event);
       break;
     }
     case GST_EVENT_RECONFIGURE:
     case GST_EVENT_FLUSH_STOP:{
-      GstIterator *it;
-
-      it = gst_element_iterate_sink_pads (GST_ELEMENT (self));
-      while (gst_iterator_foreach (it, flush_sinkpad,
-              GINT_TO_POINTER (FALSE)) == GST_ITERATOR_RESYNC)
-        gst_iterator_resync (it);
-      gst_iterator_free (it);
+      flush_sinkpads (self, FALSE);
 
       gst_data_queue_set_flushing (self->outbound_sctp_packet_queue, FALSE);
       self->need_segment = TRUE;
@@ -977,7 +978,6 @@ sctpenc_cleanup (GstSctpEnc * self)
 
   g_signal_handler_disconnect (self->sctp_association,
       self->signal_handler_state_changed);
-  stop_srcpad_task (self->src_pad, self);
   gst_sctp_association_force_close (self->sctp_association);
   g_object_unref (self->sctp_association);
   self->sctp_association = NULL;