[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