[vlc-devel] [PATCH 2/2] decoder: fix input_DecoderWait deadlock

Thomas Guillem thomas at gllm.fr
Fri Dec 11 14:17:10 CET 2015


I don't feely ready to get rid of input_DecoderWait and rewrite es_out, at
least, not for 3.0.

With this patch, input_DecoderWait will only lock one mutex, the owner one, and
will be signaled when the decoder is idle and has nothing to decode.
---
 src/input/decoder.c | 45 +++++++++++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/src/input/decoder.c b/src/input/decoder.c
index 17cedcf..efdca84 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -106,6 +106,8 @@ struct decoder_owner_sys_t
 
     /* Waiting */
     bool b_waiting;
+    /* atomic in order to avoid a double lock from lock and fifo */
+    atomic_bool wait_abort;
     bool b_first;
     bool b_has_data;
 
@@ -113,7 +115,6 @@ struct decoder_owner_sys_t
     bool flushing;
     bool b_draining;
     atomic_bool drained;
-    bool b_idle;
 
     /* CC */
     struct
@@ -1474,10 +1475,21 @@ static void *DecoderThread( void *p_data )
         if( p_block == NULL )
         {
             if( likely(!p_owner->b_draining) )
-            {   /* Wait for a block to decode (or a request to drain) */
-                p_owner->b_idle = true;
+            {
+                /* Wake up and abort input_DecoderWait */
+                if( !atomic_exchange( &p_owner->wait_abort, true ) )
+                {
+                    vlc_fifo_Unlock( p_owner->p_fifo );
+                    vlc_mutex_lock( &p_owner->lock );
+                    vlc_cond_signal( &p_owner->wait_acknowledge );
+                    vlc_mutex_unlock( &p_owner->lock );
+
+                    vlc_fifo_Lock( p_owner->p_fifo );
+                    continue;
+                }
+
+                /* Wait for a block to decode (or a request to drain) */
                 vlc_fifo_Wait( p_owner->p_fifo );
-                p_owner->b_idle = false;
                 continue;
             }
             /* We have emptied the FIFO and there is a pending request to
@@ -1560,13 +1572,13 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
     p_owner->frames_countdown = 0;
 
     p_owner->b_waiting = false;
+    atomic_init( &p_owner->wait_abort, false );
     p_owner->b_first = true;
     p_owner->b_has_data = false;
 
     p_owner->flushing = false;
     p_owner->b_draining = false;
     atomic_init( &p_owner->drained, false );
-    p_owner->b_idle = false;
 
     es_format_Init( &p_owner->fmt, UNKNOWN_ES, 0 );
 
@@ -1915,6 +1927,7 @@ void input_DecoderDecode( decoder_t *p_dec, block_t *p_block, bool b_do_pace )
             vlc_fifo_WaitCond( p_owner->p_fifo, &p_owner->wait_fifo );
     }
 
+    atomic_store( &p_owner->wait_abort, false );
     vlc_fifo_QueueUnlocked( p_owner->p_fifo, p_block );
     vlc_fifo_Unlock( p_owner->p_fifo );
 }
@@ -2119,6 +2132,7 @@ void input_DecoderStopWait( decoder_t *p_dec )
 
     vlc_mutex_lock( &p_owner->lock );
     p_owner->b_waiting = false;
+    atomic_store( &p_owner->wait_abort, false );
     vlc_cond_signal( &p_owner->wait_request );
     vlc_mutex_unlock( &p_owner->lock );
 }
@@ -2130,22 +2144,13 @@ void input_DecoderWait( decoder_t *p_dec )
     assert( p_owner->b_waiting );
 
     vlc_mutex_lock( &p_owner->lock );
-    while( !p_owner->b_has_data )
-    {
-        /* Don't need to lock p_owner->paused since it's only modified by the
-         * owner */
-        if( p_owner->paused )
-            break;
-        vlc_fifo_Lock( p_owner->p_fifo );
-        if( p_owner->b_idle && vlc_fifo_IsEmpty( p_owner->p_fifo ) )
-        {
-            msg_Err( p_dec, "buffer deadlock prevented" );
-            vlc_fifo_Unlock( p_owner->p_fifo );
-            break;
-        }
-        vlc_fifo_Unlock( p_owner->p_fifo );
+
+    /* Wait until decoder has data, decoder is paused or wait is aborted.
+     * Don't need to lock p_owner->paused with fifo lock since it's only
+     * modified by the owner */
+    while( !p_owner->b_has_data && !p_owner->paused
+        && !atomic_load( &p_owner->wait_abort ) )
         vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock );
-    }
     vlc_mutex_unlock( &p_owner->lock );
 }
 
-- 
2.1.4



More information about the vlc-devel mailing list