[vlc-devel] [PATCH 1/9] preparser: interrupt the thread by stopping input_thread_t

Thomas Guillem thomas at gllm.fr
Sun Jun 5 11:41:42 CEST 2016


---
 src/playlist/preparser.c | 61 ++++++++++++++++++++++++++++--------------------
 1 file changed, 36 insertions(+), 25 deletions(-)

diff --git a/src/playlist/preparser.c b/src/playlist/preparser.c
index 5315dc4..f360a47 100644
--- a/src/playlist/preparser.c
+++ b/src/playlist/preparser.c
@@ -25,6 +25,8 @@
 # include "config.h"
 #endif
 
+#include <assert.h>
+
 #include <vlc_common.h>
 
 #include "fetcher.h"
@@ -47,9 +49,12 @@ struct playlist_preparser_t
     vlc_object_t        *object;
     playlist_fetcher_t  *p_fetcher;
 
+    input_thread_t      *input;
+    bool                 input_done;
+
     vlc_mutex_t     lock;
     vlc_cond_t      wait;
-    vlc_sem_t       item_done;
+    vlc_cond_t      thread_wait;
     bool            b_live;
     preparser_entry_t  **pp_waiting;
     int             i_waiting;
@@ -66,6 +71,8 @@ playlist_preparser_t *playlist_preparser_New( vlc_object_t *parent )
     if( !p_preparser )
         return NULL;
 
+    p_preparser->input = NULL;
+    p_preparser->input_done = false;
     p_preparser->object = parent;
     p_preparser->p_fetcher = playlist_fetcher_New( parent );
     if( unlikely(p_preparser->p_fetcher == NULL) )
@@ -73,7 +80,7 @@ playlist_preparser_t *playlist_preparser_New( vlc_object_t *parent )
 
     vlc_mutex_init( &p_preparser->lock );
     vlc_cond_init( &p_preparser->wait );
-    vlc_sem_init( &p_preparser->item_done, 0 );
+    vlc_cond_init( &p_preparser->thread_wait );
     p_preparser->b_live = false;
     p_preparser->i_waiting = 0;
     p_preparser->pp_waiting = NULL;
@@ -125,14 +132,15 @@ void playlist_preparser_Delete( playlist_preparser_t *p_preparser )
         REMOVE_ELEM( p_preparser->pp_waiting, p_preparser->i_waiting, 0 );
     }
 
-    vlc_sem_post( &p_preparser->item_done );
+    if( p_preparser->input != NULL )
+        input_Stop( p_preparser->input );
 
     while( p_preparser->b_live )
         vlc_cond_wait( &p_preparser->wait, &p_preparser->lock );
     vlc_mutex_unlock( &p_preparser->lock );
 
     /* Destroy the item preparser */
-    vlc_sem_destroy( &p_preparser->item_done );
+    vlc_cond_destroy( &p_preparser->thread_wait );
     vlc_cond_destroy( &p_preparser->wait );
     vlc_mutex_destroy( &p_preparser->lock );
 
@@ -148,11 +156,14 @@ void playlist_preparser_Delete( playlist_preparser_t *p_preparser )
 static int InputEvent( vlc_object_t *obj, const char *varname,
                        vlc_value_t old, vlc_value_t cur, void *data )
 {
-    vlc_sem_t *done = data;
+    playlist_preparser_t *preparser = data;
     int event = cur.i_int;
 
     if( event == INPUT_EVENT_DEAD )
-        vlc_sem_post( done );
+    {
+        preparser->input_done = true;
+        vlc_cond_signal( &preparser->thread_wait );
+    }
 
     (void) obj; (void) varname; (void) old;
     return VLC_SUCCESS;
@@ -183,25 +194,26 @@ static void Preparse( playlist_preparser_t *preparser, input_item_t *p_item,
     /* Do not preparse if it is already done (like by playing it) */
     if( b_preparse && !input_item_IsPreparsed( p_item ) )
     {
-        input_thread_t *input = input_CreatePreparser( preparser->object,
-                                                       p_item );
-        if( input == NULL )
+        preparser->input = input_CreatePreparser( preparser->object, p_item );
+        if( preparser->input == NULL )
         {
             input_item_SignalPreparseEnded( p_item, ITEM_PREPARSE_FAILED );
             return;
         }
+        preparser->input_done = false;
+
+        var_AddCallback( preparser->input, "intf-event", InputEvent,
+                         preparser );
+        if( input_Start( preparser->input ) == VLC_SUCCESS )
+        {
+            while( !preparser->input_done )
+                vlc_cond_wait( &preparser->thread_wait, &preparser->lock );
+        }
 
-        var_AddCallback( input, "intf-event", InputEvent,
-                         &preparser->item_done );
-        if( input_Start( input ) == VLC_SUCCESS )
-            vlc_sem_wait( &preparser->item_done );
-        var_DelCallback( input, "intf-event", InputEvent,
-                         &preparser->item_done );
-        /* Normally, the input is already stopped since we waited for it. But
-         * if the playlist preparser is being deleted, then the input might
-         * still be running. Force it to stop. */
-        input_Stop( input );
-        input_Close( input );
+        var_DelCallback( preparser->input, "intf-event", InputEvent,
+                         preparser );
+        input_Close( preparser->input );
+        preparser->input = NULL;
 
         var_SetAddress( preparser->object, "item-change", p_item );
         input_item_SetPreparsed( p_item, true );
@@ -260,13 +272,13 @@ static void *Thread( void *data )
 {
     playlist_preparser_t *p_preparser = data;
 
+    vlc_mutex_lock( &p_preparser->lock );
     for( ;; )
     {
         input_item_t *p_current;
         input_item_meta_request_option_t i_options;
 
         /* */
-        vlc_mutex_lock( &p_preparser->lock );
         if( p_preparser->i_waiting > 0 )
         {
             preparser_entry_t *p_entry = p_preparser->pp_waiting[0];
@@ -280,17 +292,16 @@ static void *Thread( void *data )
             p_current = NULL;
             p_preparser->b_live = false;
             vlc_cond_signal( &p_preparser->wait );
-        }
-        vlc_mutex_unlock( &p_preparser->lock );
-
-        if( !p_current )
             break;
+        }
+        assert( p_current );
 
         Preparse( p_preparser, p_current, i_options );
 
         Art( p_preparser, p_current );
         vlc_gc_decref(p_current);
     }
+    vlc_mutex_unlock( &p_preparser->lock );
     return NULL;
 }
 
-- 
2.8.1



More information about the vlc-devel mailing list