X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fmodules.c;h=ecd1d58a4d5cd143c5dec4918fed7c728e60aee7;hb=145b1961b4825d2a8d807bf02db90440a8c45380;hp=fd08b1056dedb6224a81967559209649d2012eb8;hpb=19ea8feb6db01c1deafb19f35ecee8eff81aeb02;p=vlc diff --git a/src/misc/modules.c b/src/misc/modules.c index fd08b1056d..ecd1d58a4d 100644 --- a/src/misc/modules.c +++ b/src/misc/modules.c @@ -2,7 +2,7 @@ * modules.c : Builtin and plugin modules management functions ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: modules.c,v 1.77 2002/08/04 17:23:44 sam Exp $ + * $Id: modules.c,v 1.94 2002/10/03 13:21:55 sam Exp $ * * Authors: Samuel Hocevar * Ethan C. Baldridge @@ -36,6 +36,11 @@ #include #include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif #if defined(HAVE_DLFCN_H) /* Linux, BSD, Hurd */ # include /* dlopen(), dlsym(), dlclose() */ @@ -65,6 +70,9 @@ #include "video_output.h" #include "audio_output.h" +#include "aout_internal.h" + +#include "stream_output.h" #include "iso_lang.h" @@ -83,15 +91,12 @@ *****************************************************************************/ #ifdef HAVE_DYNAMIC_PLUGINS static void AllocateAllPlugins ( vlc_object_t * ); -static void AllocatePluginDir ( vlc_object_t *, const char * ); +static void AllocatePluginDir ( vlc_object_t *, const char *, int ); static int AllocatePluginFile ( vlc_object_t *, char * ); #endif static int AllocateBuiltinModule( vlc_object_t *, int ( * ) ( module_t * ) ); static int DeleteModule ( module_t * ); -static int LockModule ( module_t * ); -static int UnlockModule ( module_t * ); #ifdef HAVE_DYNAMIC_PLUGINS -static int HideModule ( module_t * ); static void DupModule ( module_t * ); static void UndupModule ( module_t * ); static int CallEntry ( module_t * ); @@ -110,10 +115,6 @@ void __module_InitBank( vlc_object_t *p_this ) p_bank = vlc_object_create( p_this, sizeof(module_bank_t) ); p_bank->psz_object_name = "module bank"; - p_bank->first = NULL; - p_bank->i_count = 0; - vlc_mutex_init( p_this, &p_bank->lock ); - /* * Store the symbols to be exported */ @@ -122,8 +123,8 @@ void __module_InitBank( vlc_object_t *p_this ) #endif /* Everything worked, attach the object */ - p_this->p_vlc->p_module_bank = p_bank; - vlc_object_attach( p_bank, p_this->p_vlc ); + p_this->p_libvlc->p_module_bank = p_bank; + vlc_object_attach( p_bank, p_this->p_libvlc ); return; } @@ -150,27 +151,25 @@ void __module_EndBank( vlc_object_t *p_this ) { module_t * p_next; - vlc_object_detach_all( p_this->p_vlc->p_module_bank ); + vlc_object_detach( p_this->p_libvlc->p_module_bank ); - while( p_this->p_vlc->p_module_bank->first != NULL ) + while( p_this->p_libvlc->p_module_bank->i_children ) { - if( DeleteModule( p_this->p_vlc->p_module_bank->first ) ) + p_next = (module_t *)p_this->p_libvlc->p_module_bank->pp_children[0]; + + if( DeleteModule( p_next ) ) { /* Module deletion failed */ msg_Err( p_this, "module \"%s\" can't be removed, trying harder", - p_this->p_vlc->p_module_bank->first->psz_object_name ); + p_next->psz_object_name ); /* We just free the module by hand. Niahahahahaha. */ - p_next = p_this->p_vlc->p_module_bank->first->next; - free( p_this->p_vlc->p_module_bank->first ); - p_this->p_vlc->p_module_bank->first = p_next; + vlc_object_detach( p_next ); + vlc_object_destroy( p_next ); } } - /* Destroy the lock */ - vlc_mutex_destroy( &p_this->p_vlc->p_module_bank->lock ); - - vlc_object_destroy( p_this->p_vlc->p_module_bank ); + vlc_object_destroy( p_this->p_libvlc->p_module_bank ); return; } @@ -212,51 +211,6 @@ void __module_LoadPlugins( vlc_object_t * p_this ) #endif } -/***************************************************************************** - * module_ManageBank: manage the module bank. - ***************************************************************************** - * This function parses the module bank and hides modules that have been - * unused for a while. - *****************************************************************************/ -void __module_ManageBank( vlc_object_t *p_this ) -{ -#ifdef HAVE_DYNAMIC_PLUGINS - module_t * p_module; - - /* We take the global lock */ - vlc_mutex_lock( &p_this->p_vlc->p_module_bank->lock ); - - /* Parse the module list to see if any modules need to be unloaded */ - for( p_module = p_this->p_vlc->p_module_bank->first ; - p_module != NULL ; - p_module = p_module->next ) - { - /* If the module is unused and if it is a plugin module... */ - if( p_module->i_usage == 0 && !p_module->b_builtin ) - { - if( p_module->i_unused_delay < MODULE_HIDE_DELAY ) - { - p_module->i_unused_delay++; - } - else - { - msg_Dbg( p_this, "hiding unused plugin module \"%s\"", - p_module->psz_object_name ); - HideModule( p_module ); - - /* Break here, so that we only hide one module at a time */ - break; - } - } - } - - /* We release the global lock */ - vlc_mutex_unlock( &p_this->p_vlc->p_module_bank->lock ); -#endif /* HAVE_DYNAMIC_PLUGINS */ - - return; -} - /***************************************************************************** * module_Need: return the best module function, given a capability list. ***************************************************************************** @@ -275,17 +229,26 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, }; module_list_t *p_list, *p_first, *p_tmp; + vlc_list_t *p_all; int i_index = 0; vlc_bool_t b_intf = VLC_FALSE; module_t *p_module; + module_t **pp_parser; int i_shortcuts = 0; - char *psz_shortcuts = NULL; + char *psz_shortcuts = NULL, *psz_var = NULL; msg_Dbg( p_this, "looking for %s module", psz_capability ); + /* Deal with variables */ + if( psz_name && psz_name[0] == '$' ) + { + psz_var = config_GetPsz( p_this, psz_name + 1 ); + psz_name = psz_var; + } + /* Count how many different shortcuts were asked for */ if( psz_name && *psz_name ) { @@ -294,6 +257,7 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, /* If the user wants none, give him none. */ if( !strcmp( psz_name, "none" ) ) { + if( psz_var ) free( psz_var ); return NULL; } @@ -310,22 +274,19 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, } } - /* We take the global lock */ - vlc_mutex_lock( &p_this->p_vlc->p_module_bank->lock ); - /* Sort the modules and test them */ - p_list = malloc( p_this->p_vlc->p_module_bank->i_count - * sizeof( module_list_t ) ); + p_all = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE ); + p_list = malloc( p_all->i_count * sizeof( module_list_t ) ); p_first = NULL; /* Parse the module list for capabilities and probe each of them */ - for( p_module = p_this->p_vlc->p_module_bank->first ; - p_module != NULL ; - p_module = p_module->next ) + for( pp_parser = (module_t**)p_all->pp_objects ; *pp_parser ; pp_parser++ ) { module_t * p_submodule = NULL; int i_shortcut_bonus = 0, i_submodule; + p_module = *pp_parser; + /* Test that this module can do what we need */ if( strcmp( p_module->psz_capability, psz_capability ) ) { @@ -338,7 +299,6 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, { p_submodule = (module_t*)p_module->pp_children[ i_submodule ]; - p_submodule->next = p_module->next; break; } } @@ -459,16 +419,16 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, msg_Dbg( p_this, "probing %i candidate%s", i_index, i_index == 1 ? "" : "s" ); - /* Lock all selected modules */ + /* Lock all candidate modules */ p_tmp = p_first; while( p_tmp != NULL ) { - LockModule( p_tmp->p_module ); + vlc_object_yield( p_tmp->p_module ); p_tmp = p_tmp->p_next; } - /* We can release the global lock, module refcounts were incremented */ - vlc_mutex_unlock( &p_this->p_vlc->p_module_bank->lock ); + /* We can release the list, interesting modules were yielded */ + vlc_list_release( p_all ); /* Parse the linked list and use the first successful module */ p_tmp = p_first; @@ -480,7 +440,7 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, break; } - UnlockModule( p_tmp->p_module ); + vlc_object_release( p_tmp->p_module ); p_tmp = p_tmp->p_next; } @@ -498,7 +458,7 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, /* Unlock the remaining modules */ while( p_tmp != NULL ) { - UnlockModule( p_tmp->p_module ); + vlc_object_release( p_tmp->p_module ); p_tmp = p_tmp->p_next; } @@ -525,6 +485,11 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, free( psz_shortcuts ); } + if( psz_var ) + { + free( psz_var ); + } + /* Don't forget that the module is still locked */ return p_module; } @@ -543,17 +508,9 @@ void __module_Unneed( vlc_object_t * p_this, module_t * p_module ) p_module->pf_deactivate( p_this ); } - /* We take the global lock */ - vlc_mutex_lock( &p_module->p_vlc->p_module_bank->lock ); - - /* Just unlock the module - we can't do anything if it fails, - * so there is no need to check the return value. */ - UnlockModule( p_module ); - msg_Info( p_module, "unlocking module \"%s\"", p_module->psz_object_name ); - /* We release the global lock */ - vlc_mutex_unlock( &p_module->p_vlc->p_module_bank->lock ); + vlc_object_release( p_module ); return; } @@ -569,7 +526,8 @@ void __module_Unneed( vlc_object_t * p_this, module_t * p_module ) static void AllocateAllPlugins( vlc_object_t *p_this ) { /* Yes, there are two NULLs because we replace one with "plugin-path". */ - char * path[] = { "modules", PLUGIN_PATH, NULL, NULL }; + char * path[] = { "modules", PLUGIN_PATH, "plugins", NULL, + NULL }; char ** ppsz_path = path; char * psz_fullpath; @@ -612,7 +570,8 @@ static void AllocateAllPlugins( vlc_object_t *p_this ) msg_Dbg( p_this, "recursively browsing `%s'", psz_fullpath ); - AllocatePluginDir( p_this, psz_fullpath ); + /* Don't go deeper than 5 subdirectories */ + AllocatePluginDir( p_this, psz_fullpath, 5 ); #if defined( SYS_BEOS ) || defined( SYS_DARWIN ) if( b_notinroot ) @@ -626,57 +585,71 @@ static void AllocateAllPlugins( vlc_object_t *p_this ) /***************************************************************************** * AllocatePluginDir: recursively parse a directory to look for plugins *****************************************************************************/ -static void AllocatePluginDir( vlc_object_t *p_this, const char *psz_dir ) +static void AllocatePluginDir( vlc_object_t *p_this, const char *psz_dir, + int i_maxdepth ) { -#define PLUGIN_EXT ".so" - DIR * dir; - int i_dirlen = strlen( psz_dir ); - char * psz_file; + int i_dirlen; + DIR * dir; + char * psz_file; + struct dirent * file; - if( (dir = opendir( psz_dir )) ) + if( i_maxdepth < 0 ) { - /* Parse the directory and try to load all files it contains. */ - while( (file = readdir( dir )) ) + return; + } + + dir = opendir( psz_dir ); + + if( !dir ) + { + return; + } + + i_dirlen = strlen( psz_dir ); + + /* Parse the directory and try to load all files it contains. */ + while( (file = readdir( dir )) ) + { + struct stat statbuf; + int i_len; + + /* Skip ".", ".." and anything starting with "." */ + if( !*file->d_name || *file->d_name == '.' ) { - int i_len = strlen( file->d_name ); + continue; + } - /* Skip ".", ".." and anything starting with "." */ - if( !*file->d_name || *file->d_name == '.' ) - { - continue; - } + i_len = strlen( file->d_name ); - if( file->d_type == DT_DIR ) - { - psz_file = malloc( i_dirlen + 1 /* / */ + i_len + 1 /* \0 */ ); - sprintf( psz_file, "%s/%s", psz_dir, file->d_name ); - AllocatePluginDir( p_this, psz_file ); - free( psz_file ); - } - else if( i_len > strlen( PLUGIN_EXT ) - /* We only load files ending with ".so" */ - && !strncmp( file->d_name + i_len - strlen( PLUGIN_EXT ), - PLUGIN_EXT, strlen( PLUGIN_EXT ) ) ) - { - psz_file = malloc( i_dirlen + 1 /* / */ + i_len + 1 /* \0 */ ); - sprintf( psz_file, "%s/%s", psz_dir, file->d_name ); - AllocatePluginFile( p_this, psz_file ); - free( psz_file ); - } + psz_file = malloc( i_dirlen + 1 /* / */ + i_len + 1 /* \0 */ ); + sprintf( psz_file, "%s/%s", psz_dir, file->d_name ); + + if( !stat( psz_file, &statbuf ) && statbuf.st_mode & S_IFDIR ) + { + AllocatePluginDir( p_this, psz_file, i_maxdepth - 1 ); + } + else if( i_len > strlen( LIBEXT ) + /* We only load files ending with LIBEXT */ + && !strncmp( file->d_name + i_len - strlen( LIBEXT ), + LIBEXT, strlen( LIBEXT ) ) ) + { + AllocatePluginFile( p_this, psz_file ); } - /* Close the directory if successfully opened */ - closedir( dir ); + free( psz_file ); } + + /* Close the directory */ + closedir( dir ); } /***************************************************************************** * 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, - * module_Unneed and HideModule. It can be removed by DeleteModule. + * for its information data. The module can then be handled by module_Need + * and module_Unneed. It can be removed by DeleteModule. *****************************************************************************/ static int AllocatePluginFile( vlc_object_t * p_this, char * psz_file ) { @@ -707,7 +680,7 @@ static int AllocatePluginFile( vlc_object_t * p_this, char * psz_file ) /* We need to fill these since they may be needed by CallEntry() */ p_module->psz_filename = psz_file; p_module->handle = handle; - p_module->p_symbols = &p_this->p_vlc->p_module_bank->symbols; + p_module->p_symbols = &p_this->p_libvlc->p_module_bank->symbols; /* Initialize the module: fill p_module->psz_object_name, default config */ if( CallEntry( p_module ) != 0 ) @@ -723,25 +696,12 @@ static int AllocatePluginFile( vlc_object_t * p_this, char * psz_file ) p_module->psz_longname = strdup( p_module->psz_longname ); /* Everything worked fine ! The module is ready to be added to the list. */ - p_module->i_usage = 0; - p_module->i_unused_delay = 0; - p_module->b_builtin = VLC_FALSE; - /* Link module into the linked list */ - if( p_this->p_vlc->p_module_bank->first != NULL ) - { - p_this->p_vlc->p_module_bank->first->prev = p_module; - } - p_module->next = p_this->p_vlc->p_module_bank->first; - p_module->prev = NULL; - p_this->p_vlc->p_module_bank->first = p_module; - p_this->p_vlc->p_module_bank->i_count++; - - msg_Dbg( p_this, "plugin \"%s\", %s", - p_module->psz_object_name, p_module->psz_longname ); + /* msg_Dbg( p_this, "plugin \"%s\", %s", + p_module->psz_object_name, p_module->psz_longname ); */ - vlc_object_attach( p_module, p_this->p_vlc->p_module_bank ); + vlc_object_attach( p_module, p_this->p_libvlc->p_module_bank ); return 0; } @@ -813,8 +773,8 @@ static void UndupModule( module_t *p_module ) * AllocateBuiltinModule: initialize a builtin module. ***************************************************************************** * This function registers a builtin module and allocates a structure - * for its information data. The module can then be handled by module_Need, - * module_Unneed and HideModule. It can be removed by DeleteModule. + * for its information data. The module can then be handled by module_Need + * and module_Unneed. It can be removed by DeleteModule. *****************************************************************************/ static int AllocateBuiltinModule( vlc_object_t * p_this, int ( *pf_entry ) ( module_t * ) ) @@ -841,25 +801,12 @@ static int AllocateBuiltinModule( vlc_object_t * p_this, } /* Everything worked fine ! The module is ready to be added to the list. */ - p_module->i_usage = 0; - p_module->i_unused_delay = 0; - p_module->b_builtin = VLC_TRUE; - /* Link module into the linked list */ - if( p_this->p_vlc->p_module_bank->first != NULL ) - { - p_this->p_vlc->p_module_bank->first->prev = p_module; - } - p_module->next = p_this->p_vlc->p_module_bank->first; - p_module->prev = NULL; - p_this->p_vlc->p_module_bank->first = p_module; - p_this->p_vlc->p_module_bank->i_count++; - - msg_Dbg( p_this, "builtin \"%s\", %s", - p_module->psz_object_name, p_module->psz_longname ); + /* msg_Dbg( p_this, "builtin \"%s\", %s", + p_module->psz_object_name, p_module->psz_longname ); */ - vlc_object_attach( p_module, p_this->p_vlc->p_module_bank ); + vlc_object_attach( p_module, p_this->p_libvlc->p_module_bank ); return 0; } @@ -867,68 +814,20 @@ static int AllocateBuiltinModule( vlc_object_t * p_this, /***************************************************************************** * DeleteModule: delete a module and its structure. ***************************************************************************** - * This function can only be called if i_usage <= 0. + * This function can only be called if the module isn't being used. *****************************************************************************/ static int DeleteModule( module_t * p_module ) { - /* If the module is not in use but is still in memory, we first have - * to hide it and remove it from memory before we can free the - * data structure. */ - if( p_module->b_builtin ) - { - if( p_module->i_usage != 0 ) - { - msg_Err( p_module, "trying to free builtin module \"%s\" with " - "usage %i", p_module->psz_object_name, p_module->i_usage ); - return -1; - } - } -#ifdef HAVE_DYNAMIC_PLUGINS - else - { - if( p_module->i_usage >= 1 ) - { - msg_Err( p_module, "trying to free module \"%s\" which is " - "still in use", p_module->psz_object_name ); - return -1; - } - - /* Two possibilities here: i_usage == -1 and the module is already - * unloaded, we can continue, or i_usage == 0, and we have to hide - * the module before going on. */ - if( p_module->i_usage == 0 ) - { - if( HideModule( p_module ) != 0 ) - { - return -1; - } - } - } -#endif - - vlc_object_detach_all( p_module ); - - /* Unlink the module from the linked list. */ - if( p_module->prev != NULL ) - { - p_module->prev->next = p_module->next; - } - else - { - p_module->p_vlc->p_module_bank->first = p_module->next; - } - - if( p_module->next != NULL ) - { - p_module->next->prev = p_module->prev; - } - - p_module->p_vlc->p_module_bank->i_count--; + vlc_object_detach( p_module ); /* We free the structures that we strdup()ed in Allocate*Module(). */ #ifdef HAVE_DYNAMIC_PLUGINS if( !p_module->b_builtin ) { + if( p_module->b_unloadable ) + { + module_unload( p_module->handle ); + } UndupModule( p_module ); free( p_module->psz_filename ); free( p_module->psz_longname ); @@ -939,7 +838,7 @@ static int DeleteModule( module_t * p_module ) while( p_module->i_children ) { vlc_object_t *p_this = p_module->pp_children[0]; - vlc_object_detach_all( p_this ); + vlc_object_detach( p_this ); vlc_object_destroy( p_this ); } @@ -949,125 +848,7 @@ static int DeleteModule( module_t * p_module ) return 0; } -/***************************************************************************** - * LockModule: increase the usage count of a module and load it if needed. - ***************************************************************************** - * This function has to be called before a thread starts using a module. If - * the module is already loaded, we just increase its usage count. If it isn't - * loaded, we have to dynamically open it and initialize it. - * If you successfully call LockModule() at any moment, be careful to call - * UnlockModule() when you don't need it anymore. - *****************************************************************************/ -static int LockModule( module_t * p_module ) -{ - if( p_module->i_usage >= 0 ) - { - /* This module is already loaded and activated, we can return */ - p_module->i_usage++; - return 0; - } - - if( p_module->b_builtin ) - { - /* A builtin module should always have a refcount >= 0 ! */ - msg_Err( p_module, "builtin module \"%s\" has refcount %i", - p_module->psz_object_name, p_module->i_usage ); - return -1; - } - -#ifdef HAVE_DYNAMIC_PLUGINS - if( p_module->i_usage != -1 ) - { - /* This shouldn't happen. Ever. We have serious problems here. */ - msg_Err( p_module, "plugin module \"%s\" has refcount %i", - p_module->psz_object_name, p_module->i_usage ); - return -1; - } - - /* i_usage == -1, which means that the module isn't in memory */ - if( module_load( p_module->psz_filename, &p_module->handle ) ) - { - char psz_buffer[256]; - - /* The plugin module couldn't be opened */ - msg_Err( p_module, "cannot open `%s' (%s)", - p_module->psz_filename, module_error(psz_buffer) ); - return -1; - } - - /* FIXME: what to do if the guy modified the plugin while it was - * unloaded ? It makes XMMS crash nastily, perhaps we should try - * to be a bit more clever here. */ - - /* Everything worked fine ! The module is ready to be used */ - p_module->i_usage = 1; -#endif /* HAVE_DYNAMIC_PLUGINS */ - - return 0; -} - -/***************************************************************************** - * UnlockModule: decrease the usage count of a module. - ***************************************************************************** - * We decrease the usage count of a module so that we know when a module - * becomes unused and can be hidden. - *****************************************************************************/ -static int UnlockModule( module_t * p_module ) -{ - if( p_module->i_usage <= 0 ) - { - /* This shouldn't happen. Ever. We have serious problems here. */ - msg_Err( p_module, "trying to call module_Unneed() on \"%s\" " - "which is not in use", p_module->psz_object_name ); - return -1; - } - - /* This module is still in use, we can return */ - p_module->i_usage--; - p_module->i_unused_delay = 0; - - return 0; -} - #ifdef HAVE_DYNAMIC_PLUGINS -/***************************************************************************** - * HideModule: remove a module from memory but keep its structure. - ***************************************************************************** - * This function can only be called if i_usage == 0. It will make a call - * to the module's inner module_deactivate() symbol, and then unload it - * from memory. A call to module_Need() will automagically load it again. - *****************************************************************************/ -static int HideModule( module_t * p_module ) -{ - if( p_module->b_builtin ) - { - /* A builtin module should never be hidden. */ - msg_Err( p_module, "trying to hide builtin module \"%s\"", - p_module->psz_object_name ); - return -1; - } - - if( p_module->i_usage >= 1 ) - { - msg_Err( p_module, "trying to hide module \"%s\" which is still " - "in use", p_module->psz_object_name ); - return -1; - } - - if( p_module->i_usage <= -1 ) - { - msg_Err( p_module, "trying to hide module \"%s\" which is already " - "hidden", p_module->psz_object_name ); - return -1; - } - - /* Everything worked fine, we can safely unload the module. */ - module_unload( p_module->handle ); - p_module->i_usage = -1; - - return 0; -} - /***************************************************************************** * CallEntry: call an entry point. ***************************************************************************** @@ -1081,7 +862,8 @@ static int CallEntry( module_t * p_module ) int (* pf_symbol) ( module_t * p_module ); /* Try to resolve the symbol */ - pf_symbol = module_getsymbol( p_module->handle, psz_name ); + pf_symbol = (int (*)(module_t *)) module_getsymbol( p_module->handle, + psz_name ); if( pf_symbol == NULL ) {