multiqueue: don't lock multiqueue when pushing serialized queries
authorAleix Conchillo Flaqué <aleix@oblong.com>
Wed, 8 Oct 2014 16:37:41 +0000 (09:37 -0700)
committerSebastian Dröge <sebastian@centricular.com>
Thu, 9 Oct 2014 08:49:49 +0000 (11:49 +0300)
If we are pushing a serialized query into a queue and the queue is
filled, we will end in a deadlock. We need to release the lock before
pushing and acquire it again afterward.

https://bugzilla.gnome.org/show_bug.cgi?id=737794

plugins/elements/gstmultiqueue.c

index 589053e..ccab3e3 100644 (file)
@@ -171,6 +171,7 @@ struct _GstSingleQueue
   /* for serialized queries */
   GCond query_handled;
   gboolean last_query;
+  GstQuery *last_handled_query;
 };
 
 
@@ -1268,6 +1269,7 @@ gst_single_queue_push_one (GstMultiQueue * mq, GstSingleQueue * sq,
 
     GST_MULTI_QUEUE_MUTEX_LOCK (mq);
     sq->last_query = res;
+    sq->last_handled_query = query;
     g_cond_signal (&sq->query_handled);
     GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
   } else {
@@ -1861,9 +1863,19 @@ gst_multi_queue_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
           GST_DEBUG_OBJECT (mq,
               "SingleQueue %d : Enqueuing query %p of type %s with id %d",
               sq->id, query, GST_QUERY_TYPE_NAME (query), curid);
+          GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
           res = gst_data_queue_push (sq->queue, (GstDataQueueItem *) item);
-          g_cond_wait (&sq->query_handled, &mq->qlock);
+          GST_MULTI_QUEUE_MUTEX_LOCK (mq);
+          /* it might be that the query has been taken out of the queue
+           * while we were unlocked. So, we need to check if the last
+           * handled query is the same one than the one we just
+           * pushed. If it is, we don't need to wait for the condition
+           * variable, otherwise we wait for the condition variable to
+           * be signaled. */
+          if (sq->last_handled_query != query)
+            g_cond_wait (&sq->query_handled, &mq->qlock);
           res = sq->last_query;
+          sq->last_handled_query = NULL;
         } else {
           GST_DEBUG_OBJECT (mq, "refusing query, we are buffering and the "
               "queue is not empty");