X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmodules%2Fmodules.c;h=846b804dc5a48bbce69510bc36ea9f916702a9ae;hb=553fa2da4ecc8a55cbaaefdc6ad4ed2b3eb7f48f;hp=4abb0339a1a20406cdcf877e6c181c49a95cc50a;hpb=ab8cecd821bb63fb60a568908d9c23a3f96bce8c;p=vlc diff --git a/src/modules/modules.c b/src/modules/modules.c index 4abb0339a1..846b804dc5 100644 --- a/src/modules/modules.c +++ b/src/modules/modules.c @@ -29,169 +29,20 @@ # include "config.h" #endif -#include -#include -#include -#include -#include "libvlc.h" - -#include /* free(), strtol() */ -#include /* sprintf() */ -#include /* strdup() */ -#include - -#include -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif +#include +#include #ifdef ENABLE_NLS # include #endif +#include +#include +#include +#include "libvlc.h" #include "config/configuration.h" - -#include #include "vlc_arrays.h" - #include "modules/modules.h" -static struct -{ - vlc_mutex_t lock; - module_t *head; - unsigned usage; -} modules = { VLC_STATIC_MUTEX, NULL, 0 }; - -module_t *vlc_entry__main (void); - -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -#ifdef HAVE_DYNAMIC_PLUGINS -typedef enum { CACHE_USE, CACHE_RESET, CACHE_IGNORE } cache_mode_t; -typedef struct module_bank module_bank_t; - -static void AllocateAllPlugins (vlc_object_t *); -static void AllocatePluginPath (vlc_object_t *, const char *, cache_mode_t); -static void AllocatePluginDir( vlc_object_t *, module_bank_t *, const char *, - unsigned, cache_mode_t ); -static int AllocatePluginFile( vlc_object_t *, module_bank_t *, const char *, - const struct stat *, cache_mode_t ); -static module_t *module_InitDynamic (vlc_object_t *, const char *, bool); -#endif -static module_t *module_InitStatic (vlc_plugin_cb); - -static void module_StoreBank (module_t *module) -{ - /*vlc_assert_locked (&modules.lock);*/ - module->next = modules.head; - modules.head = module; -} - -/** - * Init bank - * - * Creates a module bank structure which will be filled later - * on with all the modules found. - */ -void module_InitBank (void) -{ - vlc_mutex_lock (&modules.lock); - - if (modules.usage == 0) - { - /* Fills the module bank structure with the main module infos. - * This is very useful as it will allow us to consider the main - * library just as another module, and for instance the configuration - * options of main will be available in the module bank structure just - * as for every other module. */ - module_t *module = module_InitStatic (vlc_entry__main); - if (likely(module != NULL)) - module_StoreBank (module); - - vlc_rwlock_init (&config_lock); - config_SortConfig (); - } - modules.usage++; - - /* 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 (&modules.lock);*/ -} - -/** - * Unloads all unused plugin modules and empties the module - * bank in case of success. - */ -void module_EndBank (bool b_plugins) -{ - module_t *head = NULL; - - /* If plugins were _not_ loaded, then the caller still has the bank lock - * from module_InitBank(). */ - if( b_plugins ) - vlc_mutex_lock (&modules.lock); - /*else - vlc_assert_locked (&modules.lock); not for static mutexes :( */ - - assert (modules.usage > 0); - if (--modules.usage == 0) - { - config_UnsortConfig (); - vlc_rwlock_destroy (&config_lock); - head = modules.head; - modules.head = NULL; - } - vlc_mutex_unlock (&modules.lock); - - while (head != NULL) - { - module_t *module = head; - - head = module->next; -#ifdef HAVE_DYNAMIC_PLUGINS - if (module->b_loaded && module->b_unloadable) - { - module_Unload (module->handle); - module->b_loaded = false; - } -#endif - vlc_module_destroy (module); - } -} - -#undef module_LoadPlugins -/** - * 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 *obj) -{ - /*vlc_assert_locked (&modules.lock); not for static mutexes :( */ - -#ifdef HAVE_DYNAMIC_PLUGINS - if (modules.usage == 1) - { - msg_Dbg (obj, "searching plug-in modules"); - AllocateAllPlugins (obj); - config_UnsortConfig (); - config_SortConfig (); - } -#endif - vlc_mutex_unlock (&modules.lock); -} - /** * Checks whether a module implements a capability. * @@ -308,51 +159,6 @@ void module_stop (vlc_object_t *obj, const module_t *m) deactivate (obj); } -/** - * Frees the flat list of VLC modules. - * @param list list obtained by module_list_get() - * @param length number of items on the list - * @return nothing. - */ -void module_list_free (module_t **list) -{ - free (list); -} - -/** - * Gets the flat list of VLC modules. - * @param n [OUT] pointer to the number of modules or NULL - * @return NULL-terminated table of module pointers - * (release with module_list_free()), or NULL in case of error. - */ -module_t **module_list_get (size_t *n) -{ - /* TODO: this whole module lookup is quite inefficient */ - /* Remove this and improve module_need */ - module_t **tab = NULL; - size_t i = 0; - - for (module_t *mod = modules.head; mod; mod = mod->next) - { - module_t **nt; - nt = realloc (tab, (i + 2 + mod->submodule_count) * sizeof (*tab)); - if (nt == NULL) - { - module_list_free (tab); - return NULL; - } - - tab = nt; - tab[i++] = mod; - for (module_t *subm = mod->submodule; subm; subm = subm->next) - tab[i++] = subm; - tab[i] = NULL; - } - if (n != NULL) - *n = i; - return tab; -} - typedef struct module_list_t { module_t *p_module; @@ -526,25 +332,9 @@ found_shortcut: for (size_t i = 0; (i < count) && (p_module == NULL); i++) { module_t *p_cand = p_list[i].p_module; -#ifdef HAVE_DYNAMIC_PLUGINS - /* Make sure the module is loaded in mem */ - module_t *p_real = p_cand->parent ? p_cand->parent : p_cand; - - if (!p_real->b_loaded) - { - module_t *uncache; /* Map module in process */ - assert (p_real->psz_filename != NULL); - uncache = module_InitDynamic (p_this, p_real->psz_filename, false); - if (uncache == NULL) - { /* Corrupted module */ - msg_Err( p_this, "possibly corrupt module cache" ); - continue; - } - CacheMerge (p_this, p_real, uncache); - vlc_module_destroy (uncache); - } -#endif + if (module_Map (p_this, p_cand)) + continue; p_this->b_force = p_list[i].b_force; int ret; @@ -761,285 +551,3 @@ void module_config_free( module_config_t *config ) { free( config ); } - -/***************************************************************************** - * Following functions are local. - *****************************************************************************/ - -char *psz_vlcpath = NULL; - -#ifdef HAVE_DYNAMIC_PLUGINS - -/***************************************************************************** - * AllocateAllPlugins: load all plugin modules we can find. - *****************************************************************************/ -static void AllocateAllPlugins (vlc_object_t *p_this) -{ - const char *vlcpath = psz_vlcpath; - char *paths; - cache_mode_t mode; - - if( !var_InheritBool( p_this, "plugins-cache" ) ) - mode = CACHE_IGNORE; - else if( var_InheritBool( p_this, "reset-plugins-cache" ) ) - mode = CACHE_RESET; - else - mode = CACHE_USE; - - /* Contruct the special search path for system that have a relocatable - * executable. Set it to /plugins. */ - assert( vlcpath ); - - if( asprintf( &paths, "%s" DIR_SEP "plugins", vlcpath ) != -1 ) - { - AllocatePluginPath (p_this, paths, mode); - free( paths ); - } - - /* If the user provided a plugin path, we add it to the list */ - paths = getenv( "VLC_PLUGIN_PATH" ); - if( paths == NULL ) - return; - - paths = strdup( paths ); /* don't harm the environment ! :) */ - if( unlikely(paths == NULL) ) - return; - - for( char *buf, *path = strtok_r( paths, PATH_SEP, &buf ); - path != NULL; - path = strtok_r( NULL, PATH_SEP, &buf ) ) - AllocatePluginPath (p_this, path, mode); - - free( paths ); -} - -struct module_bank -{ - /* Plugins cache */ - size_t i_cache; - module_cache_t *cache; - - int i_loaded_cache; - module_cache_t *loaded_cache; -}; - -static void AllocatePluginPath (vlc_object_t *p_this, const char *path, - cache_mode_t mode) -{ - module_bank_t bank; - module_cache_t *cache = NULL; - size_t count = 0; - - switch( mode ) - { - case CACHE_USE: - count = CacheLoad( p_this, path, &cache ); - break; - case CACHE_RESET: - CacheDelete( p_this, path ); - break; - case CACHE_IGNORE: - msg_Dbg( p_this, "ignoring plugins cache file" ); - } - - msg_Dbg( p_this, "recursively browsing `%s'", path ); - - bank.cache = NULL; - bank.i_cache = 0; - bank.loaded_cache = cache; - bank.i_loaded_cache = count; - - /* Don't go deeper than 5 subdirectories */ - AllocatePluginDir (p_this, &bank, path, 5, mode); - - switch( mode ) - { - case CACHE_USE: - /* Discard unmatched cache entries */ - for( size_t i = 0; i < count; i++ ) - { - if (cache[i].p_module != NULL) - vlc_module_destroy (cache[i].p_module); - free (cache[i].path); - } - free( cache ); - case CACHE_RESET: - CacheSave (p_this, path, bank.cache, bank.i_cache); - case CACHE_IGNORE: - break; - } -} - -/***************************************************************************** - * AllocatePluginDir: recursively parse a directory to look for plugins - *****************************************************************************/ -static void AllocatePluginDir( vlc_object_t *p_this, module_bank_t *p_bank, - const char *psz_dir, unsigned i_maxdepth, - cache_mode_t mode ) -{ - if( i_maxdepth == 0 ) - return; - - DIR *dh = vlc_opendir (psz_dir); - if (dh == NULL) - return; - - /* Parse the directory and try to load all files it contains. */ - for (;;) - { - char *file = vlc_readdir (dh), *path; - struct stat st; - - if (file == NULL) - break; - - /* Skip ".", ".." */ - if (!strcmp (file, ".") || !strcmp (file, "..")) - { - free (file); - continue; - } - - const int pathlen = asprintf (&path, "%s"DIR_SEP"%s", psz_dir, file); - free (file); - if (pathlen == -1 || vlc_stat (path, &st)) - continue; - - if (S_ISDIR (st.st_mode)) - /* Recurse into another directory */ - AllocatePluginDir (p_this, p_bank, path, i_maxdepth - 1, mode); - else - if (S_ISREG (st.st_mode) - && strncmp (path, "lib", 3) - && ((size_t)pathlen >= sizeof ("_plugin"LIBEXT)) - && !strncasecmp (path + pathlen - strlen ("_plugin"LIBEXT), - "_plugin"LIBEXT, strlen ("_plugni"LIBEXT))) - /* ^^ We only load files matching "lib*_plugin"LIBEXT */ - AllocatePluginFile (p_this, p_bank, path, &st, mode); - - free (path); - } - closedir (dh); -} - -/***************************************************************************** - * AllocatePluginFile: load a module into memory and initialize it. - ***************************************************************************** - * This function loads a dynamically loadable module and allocates a structure - * for its information data. The module can then be handled by module_need - * and module_unneed. - *****************************************************************************/ -static int AllocatePluginFile( vlc_object_t * p_this, module_bank_t *p_bank, - const char *path, const struct stat *st, - cache_mode_t mode ) -{ - module_t * p_module = NULL; - - /* Check our plugins cache first then load plugin if needed */ - if( mode == CACHE_USE ) - p_module = CacheFind (p_bank->loaded_cache, p_bank->i_loaded_cache, - path, st); - if( p_module == NULL ) - p_module = module_InitDynamic (p_this, path, true); - if( p_module == NULL ) - return -1; - - /* We have not already scanned and inserted this module */ - assert( p_module->next == NULL ); - - /* Unload plugin until we really need it */ - if( p_module->b_loaded && p_module->b_unloadable ) - { - module_Unload( p_module->handle ); - p_module->b_loaded = false; - } - - /* For now we force loading if the module's config contains - * callbacks or actions. - * Could be optimized by adding an API call.*/ - for( size_t n = p_module->confsize, i = 0; i < n; i++ ) - if( p_module->p_config[i].i_action ) - { - /* !unloadable not allowed for plugins with callbacks */ - vlc_module_destroy (p_module); - p_module = module_InitDynamic (p_this, path, false); - break; - } - - module_StoreBank (p_module); - - if( mode == CACHE_IGNORE ) - return 0; - - /* Add entry to cache */ - CacheAdd (&p_bank->cache, &p_bank->i_cache, path, st, p_module); - /* TODO: deal with errors */ - return 0; -} - -/** - * Loads a dynamically-linked plug-in into memory and initialize it. - * - * The module can then be handled by module_need() and module_unneed(). - * - * \param path file path of the shared object - * \param fast whether to optimize loading for speed or safety - * (fast is used when the plug-in is registered but not used) - */ -static module_t *module_InitDynamic (vlc_object_t *obj, - const char *path, bool fast) -{ - module_handle_t handle; - - if (module_Load (obj, path, &handle, fast)) - return NULL; - - /* Try to resolve the symbol */ - static const char entry_name[] = "vlc_entry" MODULE_SUFFIX; - vlc_plugin_cb entry = - (vlc_plugin_cb) module_Lookup (handle, entry_name); - if (entry == NULL) - { - msg_Warn (obj, "cannot find plug-in entry point in %s", path); - goto error; - } - - /* We can now try to call the symbol */ - module_t *module = entry (); - if (unlikely(module == NULL)) - { - /* With a well-written module we shouldn't have to print an - * additional error message here, but just make sure. */ - msg_Err (obj, "cannot initialize plug-in %s", path); - goto error; - } - - module->psz_filename = strdup (path); - if (unlikely(module->psz_filename == NULL)) - { - vlc_module_destroy (module); - goto error; - } - module->handle = handle; - module->b_loaded = true; - return module; -error: - module_Unload( handle ); - return NULL; -} -#endif /* HAVE_DYNAMIC_PLUGINS */ - -/** - * Registers a statically-linked plug-in. - */ -static module_t *module_InitStatic (vlc_plugin_cb entry) -{ - /* Initializes the module */ - module_t *module = entry (); - if (unlikely (module == NULL)) - return NULL; - - module->b_loaded = true; - module->b_unloadable = false; - return module; -}