[vlc-devel] [PATCH 5/7] playlist: fix deadlock on destruction while preparser adds items to playlist

Filip Roséen filip at atch.se
Wed Mar 22 17:58:45 CET 2017


As we can have incoming requests to the preparser while we are
destroying libvlc, we can end up in a deadlock while we are removing
all playlist_item_t from the playlist, while an item being preparsed
tries to add additional items to the list.

These changes fixes the issue by introducing a preparser-deactivation
function, that will make sure that we:

 1) clear out any pending preparsing requests
 2) cancel the current item preparsing (blocking)
 3) prevent further requests to the preparser

fixes: #18151
---
 src/libvlc.c             |  3 +++
 src/playlist/preparser.c | 11 +++++++++++
 src/playlist/preparser.h |  8 ++++++++
 3 files changed, 22 insertions(+)

diff --git a/src/libvlc.c b/src/libvlc.c
index 34f24baf7f..4b220d2e31 100644
--- a/src/libvlc.c
+++ b/src/libvlc.c
@@ -507,6 +507,9 @@ void libvlc_InternalCleanup( libvlc_int_t *p_libvlc )
 {
     libvlc_priv_t *priv = libvlc_priv (p_libvlc);
 
+    if (priv->parser != NULL)
+        playlist_preparser_Deactivate(priv->parser);
+
     /* Ask the interfaces to stop and destroy them */
     msg_Dbg( p_libvlc, "removing all interfaces" );
     intf_DestroyAll( p_libvlc );
diff --git a/src/playlist/preparser.c b/src/playlist/preparser.c
index acba6f84c6..98a05b858c 100644
--- a/src/playlist/preparser.c
+++ b/src/playlist/preparser.c
@@ -36,6 +36,7 @@ struct playlist_preparser_t
     vlc_object_t* owner;
     playlist_fetcher_t* fetcher;
     struct background_worker worker;
+    atomic_bool deactivated;
 };
 
 static int InputEvent( vlc_object_t* obj, const char* varname,
@@ -112,6 +113,7 @@ playlist_preparser_t* playlist_preparser_New( vlc_object_t *parent )
 
     preparser->owner = parent;
     preparser->fetcher = playlist_fetcher_New( parent );
+    atomic_init( &preparser->deactivated, false );
 
     if( unlikely( !preparser->fetcher ) )
         msg_Warn( parent, "unable to create art fetcher" );
@@ -132,6 +134,9 @@ void playlist_preparser_Push( playlist_preparser_t *preparser,
     input_item_t *item, input_item_meta_request_option_t i_options,
     int timeout, void *id )
 {
+    if( atomic_load( &preparser->deactivated ) )
+        return; /* rejected */
+
     vlc_mutex_lock( &item->lock );
     int i_type = item->i_type;
     int b_net = item->b_net;
@@ -166,6 +171,12 @@ void playlist_preparser_Cancel( playlist_preparser_t *preparser, void *id )
     background_worker_Cancel( &preparser->worker, id );
 }
 
+void playlist_preparser_Deactivate( playlist_preparser_t* preparser )
+{
+    atomic_store( &preparser->deactivated, true );
+    background_worker_Cancel( &preparser->worker, NULL );
+}
+
 void playlist_preparser_Delete( playlist_preparser_t *preparser )
 {
     background_worker_Clean( &preparser->worker );
diff --git a/src/playlist/preparser.h b/src/playlist/preparser.h
index d1cd69ea13..48862bdfb0 100644
--- a/src/playlist/preparser.h
+++ b/src/playlist/preparser.h
@@ -75,5 +75,13 @@ void playlist_preparser_Cancel( playlist_preparser_t *, void *id );
  */
 void playlist_preparser_Delete( playlist_preparser_t * );
 
+/**
+ * This function deactivates the preparser
+ *
+ * All pending requests will be removed, and it will block until the currently
+ * running entity has finished (if any).
+ */
+void playlist_preparser_Deactivate( playlist_preparser_t * );
+
 #endif
 
-- 
2.12.0


More information about the vlc-devel mailing list