#include "modules/modules.h"
#include "modules/builtin.h"
-module_bank_t *p_module_bank;
+static module_bank_t *p_module_bank = NULL;
+static vlc_mutex_t module_lock = VLC_STATIC_MUTEX;
/*****************************************************************************
* Local prototypes
static module_t * AllocatePlugin( vlc_object_t *, char * );
#endif
static int AllocateBuiltinModule( vlc_object_t *, int ( * ) ( module_t * ) );
-static void DeleteModule ( module_t *, bool );
+static void DeleteModule ( module_bank_t *, module_t * );
#ifdef HAVE_DYNAMIC_PLUGINS
static void DupModule ( module_t * );
static void UndupModule ( module_t * );
{
module_bank_t *p_bank = NULL;
- vlc_mutex_t *lock = var_AcquireMutex( "libvlc" );
+ vlc_mutex_lock( &module_lock );
if( p_module_bank == NULL )
{
p_bank->i_usage = 1;
p_bank->i_cache = p_bank->i_loaded_cache = 0;
p_bank->pp_cache = p_bank->pp_loaded_cache = NULL;
- p_bank->b_cache = p_bank->b_cache_dirty =
- p_bank->b_cache_delete = false;
+ p_bank->b_cache = p_bank->b_cache_dirty = false;
p_bank->head = NULL;
/* Everything worked, attach the object */
else
p_module_bank->i_usage++;
- vlc_mutex_unlock( lock );
+ vlc_mutex_unlock( &module_lock );
}
{
module_bank_t *p_bank;
- vlc_mutex_t *lock = var_AcquireMutex( "libvlc" );
+ /* Save the configuration */
+ config_AutoSaveConfigFile( p_this );
+
+ vlc_mutex_lock( &module_lock );
p_bank = p_module_bank;
assert (p_bank != NULL);
if( --p_bank->i_usage > 0 )
{
- vlc_mutex_unlock( lock );
+ vlc_mutex_unlock( &module_lock );
return;
}
- /*FIXME: For thread safety, we need to:
- p_module_bank = NULL; - immediately, but that will crash the cache */
- vlc_mutex_unlock( lock );
-
- /* Save the configuration */
- config_AutoSaveConfigFile( p_this );
+ p_module_bank = NULL;
+ vlc_mutex_unlock( &module_lock );
#ifdef HAVE_DYNAMIC_PLUGINS
- if( p_bank->b_cache ) CacheSave( p_this );
+ if( p_bank->b_cache )
+ CacheSave( p_this, p_bank );
while( p_bank->i_loaded_cache-- )
{
if( p_bank->pp_loaded_cache[p_bank->i_loaded_cache] )
{
- DeleteModule(
- p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->p_module,
- p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->b_used );
+ DeleteModule( p_bank,
+ p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->p_module );
free( p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->psz_file );
free( p_bank->pp_loaded_cache[p_bank->i_loaded_cache] );
p_bank->pp_loaded_cache[p_bank->i_loaded_cache] = NULL;
#endif
while( p_bank->head != NULL )
- DeleteModule( p_bank->head, true );
+ DeleteModule( p_bank, p_bank->head );
- p_module_bank = NULL; /* FIXME: do this inside the lock */
free( p_bank );
}
*/
void __module_LoadBuiltins( vlc_object_t * p_this )
{
- vlc_mutex_t *lock = var_AcquireMutex( "libvlc" );
+ vlc_mutex_lock( &module_lock );
if( p_module_bank->b_builtins )
{
- vlc_mutex_unlock( lock );
+ vlc_mutex_unlock( &module_lock );
return;
}
p_module_bank->b_builtins = true;
- vlc_mutex_unlock( lock );
+ vlc_mutex_unlock( &module_lock );
msg_Dbg( p_this, "checking builtin modules" );
+ /* FIXME: race here - do this under the lock!! */
ALLOCATE_ALL_BUILTINS();
}
+#undef module_LoadPlugins
/**
* Load all plugins
*
* \param p_this vlc object structure
* \return nothing
*/
-void __module_LoadPlugins( vlc_object_t * p_this )
+void module_LoadPlugins( vlc_object_t * p_this, bool b_cache_delete )
{
#ifdef HAVE_DYNAMIC_PLUGINS
- vlc_mutex_t *lock = var_AcquireMutex( "libvlc" );
+ vlc_mutex_lock( &module_lock );
if( p_module_bank->b_plugins )
{
- vlc_mutex_unlock( lock );
+ vlc_mutex_unlock( &module_lock );
return;
}
p_module_bank->b_plugins = true;
- vlc_mutex_unlock( lock );
+ 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( config_GetInt( p_this, "plugins-cache" ) )
- p_module_bank->b_cache = true;
-
- if( p_module_bank->b_cache ||
- p_module_bank->b_cache_delete ) CacheLoad( p_this );
+ 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 );
#endif
}
return m->psz_help;
}
+/**
+ * Get the capability for a module
+ *
+ * \param m the module
+ * return the capability
+ */
+const char *module_get_capability( const module_t *m )
+{
+ return m->psz_capability;
+}
+
+/**
+ * Get the score for a module
+ *
+ * \param m the module
+ * return the score for the capability
+ */
+int module_get_score( const module_t *m )
+{
+ return m->i_score;
+}
+
module_t *module_hold (module_t *m)
{
vlc_hold (&m->vlc_gc_data);
/**
* Frees the flat list of VLC modules.
- * @param list list obtained by module_list_get
+ * @param list list obtained by module_list_get()
* @param length number of items on the list
* @return nothing.
*/
module_t **tab = NULL;
size_t i = 0;
+ assert (p_module_bank);
for (module_t *mod = p_module_bank->head; mod; mod = mod->next)
{
module_t **nt;
return tab;
}
+typedef struct module_list_t
+{
+ module_t *p_module;
+ int16_t i_score;
+ bool b_force;
+} module_list_t;
+
+static int modulecmp (const void *a, const void *b)
+{
+ const module_list_t *la = a, *lb = b;
+ /* Note that qsort() uses _ascending_ order,
+ * so the smallest module is the one with the biggest score. */
+ return lb->i_score - la->i_score;
+}
+
/**
* module Need
*
module_t * __module_need( vlc_object_t *p_this, const char *psz_capability,
const char *psz_name, bool b_strict )
{
- typedef struct module_list_t module_list_t;
-
stats_TimerStart( p_this, "module_need()", STATS_TIMER_MODULE_NEED );
- struct module_list_t
- {
- module_t *p_module;
- int i_score;
- bool b_force;
- module_list_t *p_next;
- };
-
- module_list_t *p_list, *p_first, *p_tmp;
-
- int i_which_module, i_index = 0;
-
+ module_list_t *p_list;
module_t *p_module;
-
- int i_shortcuts = 0;
+ int i_shortcuts = 0;
char *psz_shortcuts = NULL, *psz_var = NULL, *psz_alias = NULL;
bool b_force_backup = p_this->b_force;
-
/* Deal with variables */
if( psz_name && psz_name[0] == '$' )
{
size_t count;
module_t **p_all = module_list_get (&count);
p_list = malloc( count * sizeof( module_list_t ) );
- p_first = NULL;
unsigned i_cpu = vlc_CPU();
/* Parse the module list for capabilities and probe each of them */
- for( i_which_module = 0; i_which_module < count; i_which_module++ )
+ count = 0;
+ for (size_t i = 0; (p_module = p_all[i]) != NULL; i++)
{
- int i_shortcut_bonus = 0;
- p_module = p_all[i_which_module];
+ bool b_shortcut_bonus = false;
/* Test that this module can do what we need */
if( !module_provides( p_module, psz_capability ) )
- {
- /* Don't recurse through the sub-modules because vlc_list_find()
- * will list them anyway. */
continue;
- }
-
/* Test if we have the required CPU */
if( (p_module->i_cpu & i_cpu) != p_module->i_cpu )
- {
continue;
- }
/* If we required a shortcut, check this plugin provides it. */
if( i_shortcuts > 0 )
{
- bool b_trash;
const char *psz_name = psz_shortcuts;
- /* Let's drop modules with a <= 0 score (unless they are
- * explicitly requested) */
- b_trash = p_module->i_score <= 0;
-
for( unsigned i_short = i_shortcuts; i_short > 0; i_short-- )
{
for( unsigned i = 0; p_module->pp_shortcuts[i]; i++ )
/* Found it */
if( c && c[1] )
psz_alias = c+1;
- i_shortcut_bonus = i_short * 10000;
+ b_shortcut_bonus = true;
goto found_shortcut;
}
}
}
found_shortcut:
-
/* Store this new module */
- p_list[ i_index ].p_module = p_module;
- p_list[ i_index ].i_score = p_module->i_score + i_shortcut_bonus;
- p_list[ i_index ].b_force = i_shortcut_bonus && b_strict;
-
- /* Add it to the modules-to-probe list */
- if( i_index == 0 )
- {
- p_list[ 0 ].p_next = NULL;
- p_first = p_list;
- }
- else
- {
- /* Ok, so at school you learned that quicksort is quick, and
- * bubble sort sucks raw eggs. But that's when dealing with
- * thousands of items. Here we have barely 50. */
- module_list_t *p_newlist = p_first;
-
- if( p_first->i_score < p_list[ i_index ].i_score )
- {
- p_list[ i_index ].p_next = p_first;
- p_first = &p_list[ i_index ];
- }
- else
- {
- while( p_newlist->p_next != NULL &&
- p_newlist->p_next->i_score >= p_list[ i_index ].i_score )
- {
- p_newlist = p_newlist->p_next;
- }
-
- p_list[ i_index ].p_next = p_newlist->p_next;
- p_newlist->p_next = &p_list[ i_index ];
- }
- }
-
- i_index++;
- }
-
- msg_Dbg( p_this, "looking for %s module: %i candidate%s", psz_capability,
- i_index, i_index == 1 ? "" : "s" );
-
- /* Lock all candidate modules */
- p_tmp = p_first;
- while( p_tmp != NULL )
- {
- module_hold( p_tmp->p_module );
- p_tmp = p_tmp->p_next;
+ p_list[count].p_module = module_hold (p_module);
+ p_list[count].i_score = p_module->i_score;
+ if( b_shortcut_bonus )
+ p_list[count].i_score += 10000;
+ p_list[count].b_force = b_shortcut_bonus && b_strict;
+ count++;
}
- /* We can release the list, interesting modules were held */
+ /* We can release the list, interesting modules are held */
module_list_free (p_all);
+ /* Sort candidates by descending score */
+ qsort (p_list, count, sizeof (p_list[0]), modulecmp);
+#ifdef WIN32
+ /* FIXME: Remove this hack after finding a general solution for %z's */
+ msg_Dbg( p_this, "looking for %s module: %u candidate%s", psz_capability,
+ count, count == 1 ? "" : "s" );
+#else
+ msg_Dbg( p_this, "looking for %s module: %zu candidate%s", psz_capability,
+ count, count == 1 ? "" : "s" );
+#endif
+
/* Parse the linked list and use the first successful module */
- p_tmp = p_first;
- while( p_tmp != NULL )
+ p_module = NULL;
+ 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_module = p_tmp->p_module;
- if( p_module->b_submodule )
- p_module = p_module->parent;
+ module_t *p_real = p_cand->b_submodule ? p_cand->parent : p_cand;
- if( !p_module->b_builtin && !p_module->b_loaded )
+ if( !p_real->b_builtin && !p_real->b_loaded )
{
module_t *p_new_module =
- AllocatePlugin( p_this, p_module->psz_filename );
+ AllocatePlugin( p_this, p_real->psz_filename );
if( p_new_module )
{
- CacheMerge( p_this, p_module, p_new_module );
- DeleteModule( p_new_module, false );
+ CacheMerge( p_this, p_real, p_new_module );
+ DeleteModule( p_module_bank, p_new_module );
}
}
#endif
- p_this->b_force = p_tmp->b_force;
- if( p_tmp->p_module->pf_activate
- && p_tmp->p_module->pf_activate( p_this ) == VLC_SUCCESS )
+ p_this->b_force = p_list[i].b_force;
+ if( p_cand->pf_activate
+ && p_cand->pf_activate( p_this ) == VLC_SUCCESS )
{
- break;
+ p_module = p_cand;
+ /* Release the remaining modules */
+ while (++i < count)
+ module_release (p_list[i].p_module);
}
-
- module_release( p_tmp->p_module );
- p_tmp = p_tmp->p_next;
- }
-
- /* Store the locked module value */
- if( p_tmp != NULL )
- {
- p_module = p_tmp->p_module;
- p_tmp = p_tmp->p_next;
- }
- else
- {
- p_module = NULL;
- }
-
- /* Unlock the remaining modules */
- while( p_tmp != NULL )
- {
- module_release( p_tmp->p_module );
- p_tmp = p_tmp->p_next;
+ else
+ module_release( p_cand );
}
free( p_list );
{
msg_Dbg( p_this, "using %s module \"%s\"",
psz_capability, p_module->psz_object_name );
+ if( !p_this->psz_object_name )
+ {
+ /* This assumes that p_this is the object which will be using the
+ * module. That's not always the case ... but it is in most cases.
+ */
+ if( psz_alias )
+ p_this->psz_object_name = strdup( psz_alias );
+ else
+ p_this->psz_object_name = strdup( p_module->psz_object_name );
+ }
}
- else if( p_first == NULL )
+ else if( count == 0 )
{
- if( !strcmp( psz_capability, "access_demux" ) )
+ if( !strcmp( psz_capability, "access_demux" )
+ || !strcmp( psz_capability, "stream_filter" )
+ || !strcmp( psz_capability, "vout_window" ) )
{
- msg_Warn( p_this, "no %s module matched \"%s\"",
- psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
+ msg_Dbg( p_this, "no %s module matched \"%s\"",
+ psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
}
else
{
else
msg_StackSet( VLC_EGENERIC, "no suitable %s module", psz_capability );
- if( p_module && !p_this->psz_object_name )
- {
- /* This assumes that p_this is the object which will be using the
- * module. That's not always the case ... but it is in most cases.
- */
- if( psz_alias )
- p_this->psz_object_name = strdup( psz_alias );
- else
- p_this->psz_object_name = strdup( p_module->psz_object_name );
- }
-
free( psz_shortcuts );
free( psz_var );
* \param psz_name the name of the module
* \return a pointer to the module or NULL in case of a failure
*/
-module_t *__module_find( vlc_object_t *p_this, const char * psz_name )
+module_t *module_find( const char * psz_name )
{
module_t **list, *module;
* \param psz_name th name of the module
* \return TRUE if the module exists
*/
-bool __module_exists( vlc_object_t *p_this, const char * psz_name )
+bool module_exists (const char * psz_name)
{
- module_t *p_module = __module_find( p_this, psz_name );
+ module_t *p_module = module_find (psz_name);
if( p_module )
module_release (p_module);
- return true != NULL;
+ return p_module != NULL;
}
/**
* Return a NULL terminated array with the names of the modules
* that have a certain capability.
* Free after uses both the string and the table.
- * \param p_this vlc object structure
* \param psz_capability the capability asked
* \param pppsz_longname an pointer to an array of string to contain
the long names of the modules. If set to NULL the function don't use it.
* \return the NULL terminated array
*/
-char ** __module_GetModulesNamesForCapability( vlc_object_t *p_this,
- const char *psz_capability,
- char ***pppsz_longname )
+char ** module_GetModulesNamesForCapability( const char *psz_capability,
+ char ***pppsz_longname )
{
size_t count = 0;
char **psz_ret;
if( !psz_ret || ( pppsz_longname && *pppsz_longname == NULL ) )
{
free( psz_ret );
- free( *pppsz_longname );
- *pppsz_longname = NULL;
+ if( pppsz_longname )
+ {
+ free( *pppsz_longname );
+ *pppsz_longname = NULL;
+ }
module_list_free (list);
return NULL;
}
return path;
}
+char *psz_vlcpath = NULL;
+
/*****************************************************************************
* AllocateAllPlugins: load all plugin modules we can find.
*****************************************************************************/
#ifdef HAVE_DYNAMIC_PLUGINS
static void AllocateAllPlugins( vlc_object_t *p_this )
{
- const char *vlcpath = vlc_global()->psz_vlcpath;
+ const char *vlcpath = psz_vlcpath;
int count,i;
char * path;
vlc_array_t *arraypaths = vlc_array_new();
* Check our plugins cache first then load plugin if needed
*/
p_cache_entry =
- CacheFind( psz_file, i_file_time, i_file_size );
+ CacheFind( p_module_bank, psz_file, i_file_time, i_file_size );
if( !p_cache_entry )
{
*****************************************************************************
* This function can only be called if the module isn't being used.
*****************************************************************************/
-static void DeleteModule( module_t * p_module, bool b_detach )
+static void DeleteModule( module_bank_t *p_bank, module_t * p_module )
{
assert( p_module );
/* Unlist the module (if it is in the list) */
- module_t **pp_self = &p_module_bank->head;
+ module_t **pp_self = &p_bank->head;
while (*pp_self != NULL && *pp_self != p_module)
pp_self = &((*pp_self)->next);
if (*pp_self)