]> git.sesse.net Git - vlc/commitdiff
Keep the bank lock until plugins are loaded.
authorRémi Denis-Courmont <rdenis@simphalempin.com>
Tue, 17 Feb 2009 21:28:40 +0000 (23:28 +0200)
committerRémi Denis-Courmont <rdenis@simphalempin.com>
Tue, 17 Feb 2009 21:28:40 +0000 (23:28 +0200)
This is a bit ugly but it fixes two race conditions:
 - loading plugins while another thread is initializing,
 - using the bank when the first thread has not completed loading plugins.

Unfortunately, there is still a small race when module_need() calls
AllocatePlugin(). It really should not -need to- do that, but the fix would
be quite invasive. We would basically need to store plugin callbacks by names
rather than function pointers. Then the module descriptors would be fully
serializable, so we would not need to re-describe plugins when loading their
shared object. That would also fix the last known corruption bug in the plugins
cache.

src/libvlc.c
src/modules/modules.c
src/modules/modules.h

index 3591a909b81dc2e74c3703c73c949fab223fec8a..fb7aa5257967965797b680513ca7e971eec2b113 100644 (file)
@@ -329,7 +329,7 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
 
     if( config_LoadCmdLine( p_libvlc, &i_argc, ppsz_argv, true ) )
     {
-        module_EndBank( p_libvlc );
+        module_EndBank( p_libvlc, false );
         return VLC_EGENERIC;
     }
 
@@ -429,7 +429,7 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
     if( b_exit )
     {
         free( priv->psz_configfile );
-        module_EndBank( p_libvlc );
+        module_EndBank( p_libvlc, false );
         return i_ret;
     }
 
@@ -455,7 +455,7 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
         /* Translate "C" to the language code: "fr", "en_GB", "nl", "ru"... */
         msg_Dbg( p_libvlc, "translation test: code is \"%s\"", _("C") );
 
-        module_EndBank( p_libvlc );
+        module_EndBank( p_libvlc, false );
         module_InitBank( p_libvlc );
         if( !config_GetInt( p_libvlc, "ignore-config" ) )
             config_LoadConfigFile( p_libvlc, "main" );
@@ -541,7 +541,7 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
     if( b_exit )
     {
         free( priv->psz_configfile );
-        module_EndBank( p_libvlc );
+        module_EndBank( p_libvlc, true );
         return i_ret;
     }
 
@@ -569,7 +569,7 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
         PauseConsole();
 #endif
         free( priv->psz_configfile );
-        module_EndBank( p_libvlc );
+        module_EndBank( p_libvlc, true );
         return VLC_EGENERIC;
     }
     priv->i_verbose = config_GetInt( p_libvlc, "verbose" );
@@ -826,7 +826,7 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
         {
             module_unneed( p_libvlc, priv->p_memcpy_module );
         }
-        module_EndBank( p_libvlc );
+        module_EndBank( p_libvlc, true );
         free( priv->psz_configfile );
         return VLC_EGENERIC;
     }
@@ -1109,7 +1109,7 @@ void libvlc_InternalCleanup( libvlc_int_t *p_libvlc )
     }
 
     /* Free module bank. It is refcounted, so we call this each time  */
-    module_EndBank( p_libvlc );
+    module_EndBank( p_libvlc, true );
 
     FREENULL( priv->psz_configfile );
     var_DelCallback( p_libvlc, "key-pressed", vlc_key_to_action,
index dd026d02449fd0cae2d62bd6a74eb7f4f7e4ca72..805ea21ef4322acc76bf981f90528f1a2da99a16 100644 (file)
@@ -148,28 +148,39 @@ void __module_InitBank( vlc_object_t *p_this )
     else
         p_module_bank->i_usage++;
 
-    vlc_mutex_unlock( &module_lock );
+    /* We do retain the module bank lock until the plugins are loaded as well.
+     * This is ugly, this staged loading approach is needed: LibVLC gets
+     * some configuration parameters relevant to loading the plugins from
+     * the main (builtin) module. The module bank becomes shared read-only data
+     * once it is ready, so we need to fully serialize initialization.
+     * DO NOT UNCOMMENT the following line unless you managed to squeeze
+     * module_LoadPlugins() before you unlock the mutex. */
+    /*vlc_mutex_unlock( &module_lock );*/
 }
 
-
+#undef module_EndBank
 /**
- * End bank
- *
  * Unloads all unused plugin modules and empties the module
  * bank in case of success.
  * \param p_this vlc object structure
  * \return nothing
  */
-void __module_EndBank( vlc_object_t *p_this )
+void module_EndBank( vlc_object_t *p_this, bool b_plugins )
 {
-    module_bank_t *p_bank;
+    module_bank_t *p_bank = p_module_bank;
+
+    assert (p_bank != NULL);
 
     /* Save the configuration */
     config_AutoSaveConfigFile( p_this );
 
-    vlc_mutex_lock( &module_lock );
-    p_bank = p_module_bank;
-    assert (p_bank != NULL);
+    /* If plugins were _not_ loaded, then the caller still has the bank lock
+     * from module_InitBank(). */
+    if( b_plugins )
+        vlc_mutex_lock( &module_lock );
+    /*else
+        vlc_assert_locked( &module_lock ); not for static mutexes :( */
+
     if( --p_bank->i_usage > 0 )
     {
         vlc_mutex_unlock( &module_lock );
@@ -218,34 +229,32 @@ void __module_EndBank( vlc_object_t *p_this )
 
 #undef module_LoadPlugins
 /**
- * Load all plugins
- *
- * Load all plugin modules we can find.
+ * Loads module descriptions for all available plugins.
  * Fills the module bank structure with the plugin modules.
+ *
  * \param p_this vlc object structure
  * \return nothing
  */
 void module_LoadPlugins( vlc_object_t * p_this, bool b_cache_delete )
 {
+    module_bank_t *p_bank = p_module_bank;
+
+    assert( p_bank );
+    /*vlc_assert_locked( &module_lock ); not for static mutexes :( */
+
 #ifdef HAVE_DYNAMIC_PLUGINS
-    vlc_mutex_lock( &module_lock );
-    if( p_module_bank->b_plugins )
+    if( p_bank->i_usage == 1 )
     {
-        vlc_mutex_unlock( &module_lock );
-        return;
+        msg_Dbg( p_this, "checking plugin modules" );
+        p_module_bank->b_cache = config_GetInt( p_this, "plugins-cache" ) > 0;
+
+        if( p_module_bank->b_cache || b_cache_delete )
+            CacheLoad( p_this, p_module_bank, b_cache_delete );
+        AllocateAllPlugins( p_this, p_module_bank );
     }
+#endif
     p_module_bank->b_plugins = true;
     vlc_mutex_unlock( &module_lock );
-
-    msg_Dbg( p_this, "checking plugin modules" );
-    p_module_bank->b_cache = config_GetInt( p_this, "plugins-cache" ) > 0;
-
-    if( p_module_bank->b_cache || b_cache_delete )
-        CacheLoad( p_this, p_module_bank, b_cache_delete );
-
-    /* FIXME: race - do this under the lock */
-    AllocateAllPlugins( p_this, p_module_bank );
-#endif
 }
 
 /**
index 3e2aef7f1537aecdcc65f8f427f761235f7fb530..00836dde077124bc8c537967396cab7afe549868 100644 (file)
@@ -152,8 +152,8 @@ module_t *vlc_submodule_create (module_t *module);
 void  __module_InitBank        ( vlc_object_t * );
 void module_LoadPlugins( vlc_object_t *, bool );
 #define module_LoadPlugins(a,b) module_LoadPlugins(VLC_OBJECT(a),b)
-#define module_EndBank(a)      __module_EndBank(VLC_OBJECT(a))
-void  __module_EndBank         ( vlc_object_t * );
+void module_EndBank( vlc_object_t *, bool );
+#define module_EndBank(a,b) module_EndBank(VLC_OBJECT(a), b)
 
 /* Low-level OS-dependent handler */
 int  module_Load   (vlc_object_t *, const char *, module_handle_t *);