[vlc-commits] modules: make module_Map() lock-less on fast path

Rémi Denis-Courmont git at videolan.org
Thu Oct 27 12:12:13 CEST 2016


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Thu Oct 27 13:11:27 2016 +0300| [9b4938a2c4c1bb175d4e13115f4681df39b59008] | committer: Rémi Denis-Courmont

modules: make module_Map() lock-less on fast path

No more locking if the module requested is already loaded.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=9b4938a2c4c1bb175d4e13115f4681df39b59008
---

 src/modules/bank.c    | 122 +++++++++++++++++++++++++++++++-------------------
 src/modules/cache.c   |   5 +--
 src/modules/entry.c   |   4 +-
 src/modules/modules.c |   2 +-
 src/modules/modules.h |   6 ++-
 5 files changed, 83 insertions(+), 56 deletions(-)

diff --git a/src/modules/bank.c b/src/modules/bank.c
index 42463f1..d47e2fa 100644
--- a/src/modules/bank.c
+++ b/src/modules/bank.c
@@ -73,7 +73,7 @@ static vlc_plugin_t *module_InitStatic(vlc_plugin_cb entry)
         return NULL;
 
     assert(lib->module != NULL);
-    lib->loaded = true;
+    atomic_init(&lib->loaded, true);
     lib->unloadable = false;
     return lib;
 }
@@ -155,7 +155,7 @@ static vlc_plugin_t *module_InitDynamic(vlc_object_t *obj, const char *path,
         goto error;
     }
     plugin->handle = handle;
-    plugin->loaded = true;
+    atomic_init(&plugin->loaded, true);
     return plugin;
 error:
     module_Unload( handle );
@@ -212,7 +212,7 @@ static int AllocatePluginFile (module_bank_t *bank, const char *abspath,
     /* For now we force loading if the module's config contains callbacks.
      * Could be optimized by adding an API call.*/
     for (size_t i = 0; i < plugin->conf.size; i++)
-         if (!plugin->loaded
+         if (!atomic_load_explicit(&plugin->loaded, memory_order_relaxed)
           && plugin->conf.items[i].list_count == 0
           && (plugin->conf.items[i].list.psz_cb != NULL
            || plugin->conf.items[i].list.i_cb != NULL))
@@ -403,6 +403,77 @@ static void AllocateAllPlugins (vlc_object_t *p_this)
 
     free( paths );
 }
+
+/**
+ * Ensures that a plug-in is loaded.
+ *
+ * \note This function is thread-safe but not re-entrant.
+ *
+ * \return 0 on success, -1 on failure
+ */
+int module_Map(vlc_object_t *obj, vlc_plugin_t *plugin)
+{
+    static vlc_mutex_t lock = VLC_STATIC_MUTEX;
+
+    if (atomic_load_explicit(&plugin->loaded, memory_order_acquire))
+        return 0;
+
+    vlc_plugin_t *uncache;
+
+    assert(plugin->abspath != NULL);
+    uncache = module_InitDynamic(obj, plugin->abspath, false);
+    if (uncache == NULL)
+    {
+        msg_Err(obj, "corrupt module: %s", plugin->abspath);
+        return -1;
+    }
+
+    assert(uncache->module != NULL);
+
+    vlc_mutex_lock(&lock);
+    if (!atomic_load_explicit(&plugin->loaded, memory_order_relaxed))
+    {
+        CacheMerge(obj, plugin->module, uncache->module);
+        atomic_store_explicit(&plugin->loaded, true, memory_order_release);
+    }
+    else
+        uncache = NULL;
+    vlc_mutex_unlock(&lock);
+
+    if (likely(uncache != NULL))
+        vlc_plugin_destroy(uncache);
+
+    return 0;
+}
+
+/**
+ * Ensures that a module is not loaded.
+ *
+ * \note This function is not thread-safe. The caller must ensure that the
+ * plug-in is no longer used before calling this function.
+ */
+static void module_Unmap(vlc_plugin_t *plugin)
+{
+    if (!plugin->unloadable)
+        return;
+    if (!atomic_exchange_explicit(&plugin->loaded, false,
+                                  memory_order_acquire))
+        return;
+
+    assert(plugin->handle != NULL);
+    module_Unload(plugin->handle);
+}
+#else
+int module_Map(vlc_object_t *obj, module_t *module)
+{
+    (void) obj; (void) module;
+    return 0;
+}
+
+static void module_Unmap(vlc_plugin_t *plugin)
+{
+    (void) plugin;
+}
 #endif /* HAVE_DYNAMIC_PLUGINS */
 
 /**
@@ -472,14 +543,7 @@ void module_EndBank (bool b_plugins)
         vlc_plugin_t *lib = libs;
 
         libs = lib->next;
-#ifdef HAVE_DYNAMIC_PLUGINS
-        assert(lib->module != NULL);
-        if (lib->loaded && lib->unloadable)
-        {
-            module_Unload(lib->handle);
-            lib->loaded = false;
-        }
-#endif
+        module_Unmap(lib);
         vlc_plugin_destroy(lib);
     }
 
@@ -620,39 +684,3 @@ ssize_t module_list_cap (module_t ***restrict list, const char *cap)
     qsort (*list, n, sizeof (*tab), modulecmp);
     return n;
 }
-
-/**
- * Makes sure the module is loaded in memory.
- * \return 0 on success, -1 on failure
- */
-int module_Map (vlc_object_t *obj, module_t *module)
-{
-    static vlc_mutex_t lock = VLC_STATIC_MUTEX;
-    vlc_plugin_t *plugin = module->plugin;
-
-    assert(plugin != NULL);
-
-    vlc_mutex_lock(&lock);
-    if (!plugin->loaded)
-    {
-        vlc_plugin_t *uncache;
-
-        assert(plugin->abspath != NULL);
-#ifdef HAVE_DYNAMIC_PLUGINS
-        uncache = module_InitDynamic(obj, plugin->abspath, false);
-        if (uncache != NULL)
-        {
-            assert(uncache->module != NULL);
-            CacheMerge(obj, plugin->module, uncache->module);
-            vlc_plugin_destroy(uncache);
-        }
-        else
-#endif
-        {
-            msg_Err(obj, "corrupt module: %s", plugin->abspath);
-            module = NULL;
-        }
-    }
-    vlc_mutex_unlock(&lock);
-    return -(module == NULL);
-}
diff --git a/src/modules/cache.c b/src/modules/cache.c
index b2163e0..24f2295 100644
--- a/src/modules/cache.c
+++ b/src/modules/cache.c
@@ -747,10 +747,7 @@ void CacheMerge( vlc_object_t *p_this, module_t *p_cache, module_t *p_module )
     }
 
     p_cache->plugin->handle = p_module->plugin->handle;
-    assert(!p_cache->plugin->loaded);
-    p_cache->plugin->loaded = true;
-    assert(p_module->plugin->loaded);
-    p_module->plugin->loaded = false;
+    atomic_init(&p_module->plugin->loaded, false);
 }
 
 /**
diff --git a/src/modules/entry.c b/src/modules/entry.c
index 21b4620..1721e81 100644
--- a/src/modules/entry.c
+++ b/src/modules/entry.c
@@ -95,7 +95,7 @@ vlc_plugin_t *vlc_plugin_create(void)
     plugin->conf.count = 0;
     plugin->conf.booleans = 0;
     plugin->abspath = NULL;
-    plugin->loaded = false;
+    atomic_init(&plugin->loaded, false);
     plugin->unloadable = true;
     plugin->handle = NULL;
     plugin->abspath = NULL;
@@ -113,7 +113,7 @@ vlc_plugin_t *vlc_plugin_create(void)
 void vlc_plugin_destroy(vlc_plugin_t *plugin)
 {
     assert(plugin != NULL);
-    assert(!plugin->loaded || !plugin->unloadable);
+    assert(!plugin->unloadable || !atomic_load(&plugin->loaded));
 
     if (plugin->module != NULL)
         vlc_module_destroy(plugin->module);
diff --git a/src/modules/modules.c b/src/modules/modules.c
index 62b50a8..a62ef82 100644
--- a/src/modules/modules.c
+++ b/src/modules/modules.c
@@ -172,7 +172,7 @@ static int module_load (vlc_object_t *obj, module_t *m,
 {
     int ret = VLC_SUCCESS;
 
-    if (module_Map (obj, m))
+    if (module_Map(obj, m->plugin))
         return VLC_EGENERIC;
 
     if (m->pf_activate != NULL)
diff --git a/src/modules/modules.h b/src/modules/modules.h
index 1a0f5d3..0b59453 100644
--- a/src/modules/modules.h
+++ b/src/modules/modules.h
@@ -24,6 +24,8 @@
 #ifndef LIBVLC_MODULES_H
 # define LIBVLC_MODULES_H 1
 
+# include <vlc_atomic.h>
+
 /** The plugin handle type */
 typedef void *module_handle_t;
 
@@ -47,7 +49,7 @@ typedef struct vlc_plugin_t
         size_t booleans; /**< Number of booleal config items */
     } conf;
 
-    bool loaded; /**< Whether the plug-in is mapped in memory */
+    atomic_bool loaded; /**< Whether the plug-in is mapped in memory */
     bool unloadable; /**< Whether the plug-in can be unloaded safely */
     module_handle_t handle; /**< Run-time linker handle (if loaded) */
     char *abspath; /**< Absolute path */
@@ -109,7 +111,7 @@ void module_InitBank (void);
 size_t module_LoadPlugins( vlc_object_t * );
 #define module_LoadPlugins(a) module_LoadPlugins(VLC_OBJECT(a))
 void module_EndBank (bool);
-int module_Map (vlc_object_t *, module_t *);
+int module_Map(vlc_object_t *, vlc_plugin_t *);
 
 ssize_t module_list_cap (module_t ***, const char *);
 



More information about the vlc-commits mailing list