X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fmodules.c;h=aad88dfc4af94f2ee16a2942cfc72d251c69c14a;hb=440f9992ee947ea5fd0debbf35fdd1011c6404b3;hp=bfbf2c91cb2aec31a52d69d362176a0def7f1168;hpb=9f553534b0e8edcb711e442d3d76f8d2eb2740aa;p=vlc diff --git a/src/misc/modules.c b/src/misc/modules.c index bfbf2c91cb..aad88dfc4a 100644 --- a/src/misc/modules.c +++ b/src/misc/modules.c @@ -1,7 +1,8 @@ /***************************************************************************** - * modules.c : Built-in and dynamic modules management functions + * modules.c : Built-in and plugin modules management functions ***************************************************************************** * Copyright (C) 2001 VideoLAN + * $Id: modules.c,v 1.31 2001/05/30 17:03:12 sam Exp $ * * Authors: Samuel Hocevar * Ethan C. Baldridge @@ -24,86 +25,156 @@ #include "config.h" +/* Some faulty libcs have a broken struct dirent when _FILE_OFFSET_BITS + * is set to 64. Don't try to be cleverer. */ +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif + #include /* free(), strtol() */ #include /* sprintf() */ #include /* strdup() */ #include #if defined(HAVE_DLFCN_H) /* Linux, BSD, Hurd */ -#include /* dlopen(), dlsym(), dlclose() */ - +# include /* dlopen(), dlsym(), dlclose() */ +# define HAVE_DYNAMIC_PLUGINS #elif defined(HAVE_IMAGE_H) /* BeOS */ -#include - +# include +# define HAVE_DYNAMIC_PLUGINS #else -/* FIXME: this isn't supposed to be an error */ -#error no dynamic plugins available on your system ! +# undef HAVE_DYNAMIC_PLUGINS #endif #ifdef SYS_BEOS -#include "beos_specific.h" +# include "beos_specific.h" +#endif + +#ifdef SYS_DARWIN1_3 +# include "darwin_specific.h" #endif #include "common.h" #include "threads.h" +#include "mtime.h" +#include "tests.h" +#include "netutils.h" +#include "modules.h" + +#include "stream_control.h" +#include "input_ext-intf.h" + +#include "video.h" +#include "video_output.h" +#include "audio_output.h" + +#include "interface.h" #include "intf_msg.h" -#include "modules.h" -#include "modules_core.h" +#include "intf_playlist.h" -/* Local prototypes */ -static int AllocateDynModule( module_bank_t * p_bank, char * psz_filename ); -static int HideModule( module_t * p_module ); -static int FreeModule( module_bank_t * p_bank, module_t * p_module ); -static int LockModule( module_t * p_module ); -static int UnlockModule( module_t * p_module ); -static int CallSymbol( module_t * p_module, char * psz_name ); +#ifdef HAVE_DYNAMIC_PLUGINS +# include "modules_core.h" +#endif +#include "modules_builtin.h" +#include "modules_export.h" + +#include "main.h" /***************************************************************************** - * module_CreateBank: create the module bank. - ***************************************************************************** - * This function creates a module bank structure. + * Local prototypes *****************************************************************************/ -module_bank_t * module_CreateBank( void ) -{ - module_bank_t * p_bank; +#ifdef HAVE_DYNAMIC_PLUGINS +static int AllocatePluginModule ( char * ); +#endif +static int AllocateBuiltinModule( int ( * ) ( module_t * ), + int ( * ) ( module_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 int CallSymbol ( module_t *, char * ); +#endif - p_bank = malloc( sizeof( module_bank_t ) ); - - return( p_bank ); -} +static module_symbols_t symbols; /***************************************************************************** * module_InitBank: create the module bank. ***************************************************************************** * This function creates a module bank structure and fills it with the - * built-in modules, as well as all the dynamic modules it can find. + * built-in modules, as well as all the plugin modules it can find. *****************************************************************************/ -void module_InitBank( module_bank_t * p_bank ) +void module_InitBank( void ) { - static char * path[] = { ".", "lib", PLUGIN_PATH, NULL } ; +#ifdef HAVE_DYNAMIC_PLUGINS + static char * path[] = { ".", "lib", PLUGIN_PATH, NULL, NULL }; char ** ppsz_path = path; + char * psz_fullpath; char * psz_file; -#ifdef SYS_BEOS - char * psz_program_path = beos_GetProgramPath(); - int i_programlen = strlen( psz_program_path ); +#if defined( SYS_BEOS ) || defined( SYS_DARWIN1_3 ) + char * psz_vlcpath = system_GetProgramPath(); + int i_vlclen = strlen( psz_vlcpath ); + boolean_t b_notinroot; #endif DIR * dir; struct dirent * file; +#endif /* HAVE_DYNAMIC_PLUGINS */ + + p_module_bank->first = NULL; + vlc_mutex_init( &p_module_bank->lock ); + + /* + * Store the symbols to be exported + */ + STORE_SYMBOLS( &symbols ); + + /* + * Check all the built-in modules + */ + intf_WarnMsg( 2, "module: checking built-in modules" ); - p_bank->first = NULL; - vlc_mutex_init( &p_bank->lock ); + ALLOCATE_ALL_BUILTINS(); - intf_Msg( "module: module bank initialized" ); + /* + * Check all the plugin modules we can find + */ +#ifdef HAVE_DYNAMIC_PLUGINS + intf_WarnMsg( 2, "module: checking plugin modules" ); for( ; *ppsz_path != NULL ; ppsz_path++ ) { - if( (dir = opendir( *ppsz_path )) ) + /* Store strlen(*ppsz_path) for later use. */ + int i_dirlen = strlen( *ppsz_path ); + +#if defined( SYS_BEOS ) || defined( SYS_DARWIN1_3 ) + b_notinroot = 0; + /* Under BeOS, we need to add beos_GetProgramPath() to access + * files under the current directory */ + if( ( i_dirlen > 1 ) && strncmp( *ppsz_path, "/", 1 ) ) { - /* Store strlen(*ppsz_path) for later use. */ - int i_dirlen = strlen( *ppsz_path ); + i_dirlen += i_vlclen + 2; + b_notinroot = 1; + psz_fullpath = malloc( i_dirlen ); + if( psz_fullpath == NULL ) + { + continue; + } + sprintf( psz_fullpath, "%s/%s", psz_vlcpath, *ppsz_path ); + } + else +#endif + { + psz_fullpath = *ppsz_path; + } + + intf_WarnMsgImm( 1, "module: browsing `%s'", psz_fullpath ); + + if( (dir = opendir( psz_fullpath )) ) + { /* Parse the directory and try to load all files it contains. */ while( (file = readdir( dir )) ) { @@ -113,74 +184,67 @@ void module_InitBank( module_bank_t * p_bank ) if( i_filelen > 3 && !strncmp( file->d_name + i_filelen - 3, ".so", 3 ) ) { -#ifdef SYS_BEOS - /* Under BeOS, we need to add beos_GetProgramPath() to - * access files under the current directory */ - if( strncmp( file->d_name, "/", 1 ) ) - { - psz_file = malloc( i_programlen + i_dirlen - + i_filelen + 3 ); - if( psz_file == NULL ) - { - continue; - } - sprintf( psz_file, "%s/%s/%s", psz_programlen, - *ppsz_path, file->d_name ); - } - else -#endif + psz_file = malloc( i_dirlen + i_filelen + 2 ); + if( psz_file == NULL ) { - psz_file = malloc( i_dirlen + i_filelen + 2 ); - if( psz_file == NULL ) - { - continue; - } - sprintf( psz_file, "%s/%s", *ppsz_path, file->d_name ); + continue; } + sprintf( psz_file, "%s/%s", psz_fullpath, file->d_name ); + /* We created a nice filename -- now we just try to load - * it as a dynamic module. */ - AllocateDynModule( p_bank, psz_file ); + * it as a plugin module. */ + AllocatePluginModule( psz_file ); /* We don't care if the allocation succeeded */ free( psz_file ); } } + + /* Close the directory if successfully opened */ + closedir( dir ); } + +#if defined( SYS_BEOS ) || defined( SYS_DARWIN1_3 ) + if( b_notinroot ) + { + free( psz_fullpath ); + } +#endif } +#endif /* HAVE_DYNAMIC_PLUGINS */ + + intf_WarnMsg( 3, "module: module bank initialized" ); return; } /***************************************************************************** - * module_DestroyBank: destroy the module bank. + * module_EndBank: empty the module bank. ***************************************************************************** - * This function unloads all unused dynamic modules and removes the module + * This function unloads all unused plugin modules and empties the module * bank in case of success. *****************************************************************************/ -void module_DestroyBank( module_bank_t * p_bank ) +void module_EndBank( void ) { module_t * p_next; - while( p_bank->first != NULL ) + while( p_module_bank->first != NULL ) { - if( FreeModule( p_bank, p_bank->first ) ) + if( DeleteModule( p_module_bank->first ) ) { /* Module deletion failed */ intf_ErrMsg( "module error: `%s' can't be removed. trying harder.", - p_bank->first->psz_name ); + p_module_bank->first->psz_name ); /* We just free the module by hand. Niahahahahaha. */ - p_next = p_bank->first->next; - free(p_bank->first); - p_bank->first = p_next; + p_next = p_module_bank->first->next; + free(p_module_bank->first); + p_module_bank->first = p_next; } } /* Destroy the lock */ - vlc_mutex_destroy( &p_bank->lock ); - - /* We can free the module bank */ - free( p_bank ); + vlc_mutex_destroy( &p_module_bank->lock ); return; } @@ -188,10 +252,10 @@ void module_DestroyBank( module_bank_t * p_bank ) /***************************************************************************** * module_ResetBank: reset the module bank. ***************************************************************************** - * This function resets the module bank by unloading all unused dynamic + * This function resets the module bank by unloading all unused plugin * modules. *****************************************************************************/ -void module_ResetBank( module_bank_t * p_bank ) +void module_ResetBank( void ) { intf_ErrMsg( "FIXME: module_ResetBank unimplemented" ); return; @@ -203,19 +267,20 @@ void module_ResetBank( module_bank_t * p_bank ) * This function parses the module bank and hides modules that have been * unused for a while. *****************************************************************************/ -void module_ManageBank( module_bank_t * p_bank ) +void module_ManageBank( void ) { +#ifdef HAVE_DYNAMIC_PLUGINS module_t * p_module; /* We take the global lock */ - vlc_mutex_lock( &p_bank->lock ); + vlc_mutex_lock( &p_module_bank->lock ); /* Parse the module list to see if any modules need to be unloaded */ - for( p_module = p_bank->first ; + for( p_module = p_module_bank->first ; p_module != NULL ; p_module = p_module->next ) { - /* If the module is unused and if it is a dynamic module... */ + /* 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 ) @@ -224,15 +289,19 @@ void module_ManageBank( module_bank_t * p_bank ) } else { - intf_Msg( "module: hiding unused module `%s'", - p_module->psz_name ); + intf_WarnMsg( 1, "module: hiding unused plugin module `%s'", + p_module->psz_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_bank->lock ); + vlc_mutex_unlock( &p_module_bank->lock ); +#endif /* HAVE_DYNAMIC_PLUGINS */ return; } @@ -242,8 +311,7 @@ void module_ManageBank( module_bank_t * p_bank ) ***************************************************************************** * This function returns the module that best fits the asked capabilities. *****************************************************************************/ -module_t * module_Need( module_bank_t *p_bank, - int i_capabilities, void *p_data ) +module_t * module_Need( int i_capabilities, void *p_data ) { module_t * p_module; module_t * p_bestmodule = NULL; @@ -251,10 +319,10 @@ module_t * module_Need( module_bank_t *p_bank, int i_index; /* We take the global lock */ - vlc_mutex_lock( &p_bank->lock ); + vlc_mutex_lock( &p_module_bank->lock ); /* Parse the module list for capabilities and probe each of them */ - for( p_module = p_bank->first ; + for( p_module = p_module_bank->first ; p_module != NULL ; p_module = p_module->next ) { @@ -271,7 +339,7 @@ module_t * module_Need( module_bank_t *p_bank, if( ( (1 << i_index) & i_capabilities ) ) { i_score = ( (function_list_t *)p_module->p_functions) - [i_index].p_probe( p_data ); + [i_index].pf_probe( p_data ); if( i_score ) { @@ -305,8 +373,14 @@ module_t * module_Need( module_bank_t *p_bank, } } - /* We release the global lock */ - vlc_mutex_unlock( &p_bank->lock ); + /* We can release the global lock, module refcount was incremented */ + vlc_mutex_unlock( &p_module_bank->lock ); + + if( p_bestmodule != NULL ) + { + intf_WarnMsg( 1, "module: locking module `%s'", + p_bestmodule->psz_name ); + } /* Don't forget that the module is still locked if bestmodule != NULL */ return( p_bestmodule ); @@ -318,17 +392,19 @@ module_t * module_Need( module_bank_t *p_bank, * This function must be called by the thread that called module_Need, to * decrease the reference count and allow for hiding of modules. *****************************************************************************/ -void module_Unneed( module_bank_t * p_bank, module_t * p_module ) +void module_Unneed( module_t * p_module ) { /* We take the global lock */ - vlc_mutex_lock( &p_bank->lock ); + vlc_mutex_lock( &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 ); + intf_WarnMsg( 1, "module: unlocking module `%s'", p_module->psz_name ); + /* We release the global lock */ - vlc_mutex_unlock( &p_bank->lock ); + vlc_mutex_unlock( &p_module_bank->lock ); return; } @@ -337,14 +413,15 @@ void module_Unneed( module_bank_t * p_bank, module_t * p_module ) * Following functions are local. *****************************************************************************/ +#ifdef HAVE_DYNAMIC_PLUGINS /***************************************************************************** - * AllocateDynModule: load a module into memory and initialize it. + * AllocatePluginModule: 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 FreeModule. + * module_Unneed and HideModule. It can be removed by DeleteModule. *****************************************************************************/ -static int AllocateDynModule( module_bank_t * p_bank, char * psz_filename ) +static int AllocatePluginModule( char * psz_filename ) { module_t * p_module, * p_othermodule; module_handle_t handle; @@ -352,9 +429,9 @@ static int AllocateDynModule( module_bank_t * p_bank, char * psz_filename ) /* Try to dynamically load the module. */ if( module_load( psz_filename, &handle ) ) { - /* The dynamic module couldn't be opened */ - intf_DbgMsg( "module warning: cannot open %s (%s)", - psz_filename, module_error() ); + /* The plugin module couldn't be opened */ + intf_WarnMsgImm( 1, "module warning: cannot open %s (%s)", + psz_filename, module_error() ); return( -1 ); } @@ -369,8 +446,9 @@ static int AllocateDynModule( module_bank_t * p_bank, char * psz_filename ) } /* We need to fill these since they may be needed by CallSymbol() */ - p_module->psz_filename = psz_filename; - p_module->handle = handle; + p_module->is.plugin.psz_filename = psz_filename; + p_module->is.plugin.handle = handle; + p_module->p_symbols = &symbols; /* Initialize the module : fill p_module->psz_name, etc. */ if( CallSymbol( p_module, "InitModule" ) != 0 ) @@ -390,7 +468,7 @@ static int AllocateDynModule( module_bank_t * p_bank, char * psz_filename ) } /* Check that we don't already have a module with this name */ - for( p_othermodule = p_bank->first ; + for( p_othermodule = p_module_bank->first ; p_othermodule != NULL ; p_othermodule = p_othermodule->next ) { @@ -413,17 +491,18 @@ static int AllocateDynModule( module_bank_t * p_bank, char * psz_filename ) /* We strdup() these entries so that they are still valid when the * module is unloaded. */ - p_module->psz_filename = strdup( p_module->psz_filename ); + p_module->is.plugin.psz_filename = + strdup( p_module->is.plugin.psz_filename ); p_module->psz_name = strdup( p_module->psz_name ); p_module->psz_longname = strdup( p_module->psz_longname ); p_module->psz_version = strdup( p_module->psz_version ); - if( p_module->psz_filename == NULL + if( p_module->is.plugin.psz_filename == NULL || p_module->psz_name == NULL || p_module->psz_longname == NULL || p_module->psz_version == NULL ) { intf_ErrMsg( "module error: can't duplicate strings" ); - free( p_module->psz_filename ); + free( p_module->is.plugin.psz_filename ); free( p_module->psz_name ); free( p_module->psz_longname ); free( p_module->psz_version ); @@ -439,74 +518,129 @@ static int AllocateDynModule( module_bank_t * p_bank, char * psz_filename ) p_module->b_builtin = 0; /* Link module into the linked list */ - if( p_bank->first != NULL ) + if( p_module_bank->first != NULL ) { - p_bank->first->prev = p_module; + p_module_bank->first->prev = p_module; } - p_module->next = p_bank->first; + p_module->next = p_module_bank->first; p_module->prev = NULL; - p_bank->first = p_module; + p_module_bank->first = p_module; - intf_Msg( "module: dynamic module `%s', %s", - p_module->psz_name, p_module->psz_longname ); + /* Immediate message so that a slow module doesn't make the user wait */ + intf_WarnMsgImm( 2, "module: plugin module `%s', %s", + p_module->psz_name, p_module->psz_longname ); return( 0 ); } +#endif /* HAVE_DYNAMIC_PLUGINS */ /***************************************************************************** - * HideModule: remove a module from memory but keep its structure. + * AllocateBuiltinModule: initialize a built-in module. ***************************************************************************** - * This function can only be called if i_usage == 0. It will make a call - * to the module's inner DeactivateModule() symbol, and then unload it - * from memory. A call to module_Need() will automagically load it again. + * This function registers a built-in 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. *****************************************************************************/ -static int HideModule( module_t * p_module ) +static int AllocateBuiltinModule( int ( *pf_init ) ( module_t * ), + int ( *pf_activate ) ( module_t * ), + int ( *pf_deactivate ) ( module_t * ) ) { - if( p_module->b_builtin ) + module_t * p_module, * p_othermodule; + + /* Now that we have successfully loaded the module, we can + * allocate a structure for it */ + p_module = malloc( sizeof( module_t ) ); + if( p_module == NULL ) { - /* A built-in module should never be hidden. */ - intf_ErrMsg( "module error: trying to hide built-in module `%s'", - p_module->psz_name ); + intf_ErrMsg( "module error: can't allocate p_module" ); return( -1 ); } - if( p_module->i_usage >= 1 ) + /* Initialize the module : fill p_module->psz_name, etc. */ + if( pf_init( p_module ) != 0 ) { - intf_ErrMsg( "module error: trying to hide module `%s' which is still" - " in use", p_module->psz_name ); + /* With a well-written module we shouldn't have to print an + * additional error message here, but just make sure. */ + intf_ErrMsg( "module error: failed calling init in builtin module" ); + free( p_module ); return( -1 ); } - if( p_module->i_usage <= -1 ) + /* Check that version numbers match */ + if( strcmp( VERSION, p_module->psz_version ) ) { - intf_ErrMsg( "module error: trying to hide module `%s' which is already" - " hidden", p_module->psz_name ); + free( p_module ); return( -1 ); } - /* Deactivate the module : free the capability structure, etc. */ - if( CallSymbol( p_module, "DeactivateModule" ) != 0 ) + /* Check that we don't already have a module with this name */ + for( p_othermodule = p_module_bank->first ; + p_othermodule != NULL ; + p_othermodule = p_othermodule->next ) { - /* We couldn't call DeactivateModule() -- looks nasty, but - * we can't do much about it. Just try to unload module anyway. */ - module_unload( p_module->handle ); - p_module->i_usage = -1; + if( !strcmp( p_othermodule->psz_name, p_module->psz_name ) ) + { + free( p_module ); + return( -1 ); + } + } + + if( pf_activate( p_module ) != 0 ) + { + /* With a well-written module we shouldn't have to print an + * additional error message here, but just make sure. */ + intf_ErrMsg( "module error: failed calling activate " + "in builtin module" ); + free( p_module ); return( -1 ); } - /* Everything worked fine, we can safely unload the module. */ - module_unload( p_module->handle ); - p_module->i_usage = -1; + /* We strdup() these entries so that they are still valid when the + * module is unloaded. */ + p_module->psz_name = strdup( p_module->psz_name ); + p_module->psz_longname = strdup( p_module->psz_longname ); + p_module->psz_version = strdup( p_module->psz_version ); + if( p_module->psz_name == NULL + || p_module->psz_longname == NULL + || p_module->psz_version == NULL ) + { + intf_ErrMsg( "module error: can't duplicate strings" ); + free( p_module->psz_name ); + free( p_module->psz_longname ); + free( p_module->psz_version ); + free( p_module ); + return( -1 ); + } + + /* 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 = 1; + p_module->is.builtin.pf_deactivate = pf_deactivate; + + /* Link module into the linked list */ + if( p_module_bank->first != NULL ) + { + p_module_bank->first->prev = p_module; + } + p_module->next = p_module_bank->first; + p_module->prev = NULL; + p_module_bank->first = p_module; + + /* Immediate message so that a slow module doesn't make the user wait */ + intf_WarnMsgImm( 2, "module: builtin module `%s', %s", + p_module->psz_name, p_module->psz_longname ); return( 0 ); } /***************************************************************************** - * FreeModule: delete a module and its structure. + * DeleteModule: delete a module and its structure. ***************************************************************************** * This function can only be called if i_usage <= 0. *****************************************************************************/ -static int FreeModule( module_bank_t * p_bank, module_t * p_module ) +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 @@ -519,7 +653,13 @@ static int FreeModule( module_bank_t * p_bank, module_t * p_module ) " usage %i", p_module->psz_name, p_module->i_usage ); return( -1 ); } + else + { + /* We deactivate the module now. */ + p_module->is.builtin.pf_deactivate( p_module ); + } } +#ifdef HAVE_DYNAMIC_PLUGINS else { if( p_module->i_usage >= 1 ) @@ -540,11 +680,12 @@ static int FreeModule( module_bank_t * p_bank, module_t * p_module ) } } } +#endif /* Unlink the module from the linked list. */ - if( p_module == p_bank->first ) + if( p_module == p_module_bank->first ) { - p_bank->first = p_module->next; + p_module_bank->first = p_module->next; } if( p_module->prev != NULL ) @@ -558,7 +699,12 @@ static int FreeModule( module_bank_t * p_bank, module_t * p_module ) } /* We free the structures that we strdup()ed in Allocate*Module(). */ - free( p_module->psz_filename ); +#ifdef HAVE_DYNAMIC_PLUGINS + if( !p_module->b_builtin ) + { + free( p_module->is.plugin.psz_filename ); + } +#endif free( p_module->psz_name ); free( p_module->psz_longname ); free( p_module->psz_version ); @@ -594,20 +740,22 @@ static int LockModule( module_t * p_module ) return( -1 ); } +#ifdef HAVE_DYNAMIC_PLUGINS if( p_module->i_usage != -1 ) { /* This shouldn't happen. Ever. We have serious problems here. */ - intf_ErrMsg( "module error: dynamic module `%s' has refcount %i", + intf_ErrMsg( "module error: plugin module `%s' has refcount %i", p_module->psz_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 ) ) + if( module_load( p_module->is.plugin.psz_filename, + &p_module->is.plugin.handle ) ) { - /* The dynamic module couldn't be opened */ + /* The plugin module couldn't be opened */ intf_ErrMsg( "module error: cannot open %s (%s)", - p_module->psz_filename, module_error() ); + p_module->is.plugin.psz_filename, module_error() ); return( -1 ); } @@ -620,13 +768,14 @@ static int LockModule( module_t * p_module ) { /* We couldn't call ActivateModule() -- looks nasty, but * we can't do much about it. Just try to unload module. */ - module_unload( p_module->handle ); + module_unload( p_module->is.plugin.handle ); p_module->i_usage = -1; return( -1 ); } /* Everything worked fine ! The module is ready to be used */ p_module->i_usage = 1; +#endif /* HAVE_DYNAMIC_PLUGINS */ return( 0 ); } @@ -654,6 +803,55 @@ static int UnlockModule( module_t * p_module ) 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 DeactivateModule() 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 built-in module should never be hidden. */ + intf_ErrMsg( "module error: trying to hide built-in module `%s'", + p_module->psz_name ); + return( -1 ); + } + + if( p_module->i_usage >= 1 ) + { + intf_ErrMsg( "module error: trying to hide module `%s' which is still" + " in use", p_module->psz_name ); + return( -1 ); + } + + if( p_module->i_usage <= -1 ) + { + intf_ErrMsg( "module error: trying to hide module `%s' which is already" + " hidden", p_module->psz_name ); + return( -1 ); + } + + /* Deactivate the module : free the capability structure, etc. */ + if( CallSymbol( p_module, "DeactivateModule" ) != 0 ) + { + /* We couldn't call DeactivateModule() -- looks nasty, but + * we can't do much about it. Just try to unload module anyway. */ + module_unload( p_module->is.plugin.handle ); + p_module->i_usage = -1; + return( -1 ); + } + + /* Everything worked fine, we can safely unload the module. */ + module_unload( p_module->is.plugin.handle ); + p_module->i_usage = -1; + + return( 0 ); +} + /***************************************************************************** * CallSymbol: calls a module symbol. ***************************************************************************** @@ -663,31 +861,33 @@ static int UnlockModule( module_t * p_module ) *****************************************************************************/ static int CallSymbol( module_t * p_module, char * psz_name ) { - typedef int ( symbol_t ) ( module_t * p_module ); - symbol_t * p_symbol; + int (* pf_symbol) ( module_t * p_module ); /* Try to resolve the symbol */ - p_symbol = module_getsymbol( p_module->handle, psz_name ); + pf_symbol = module_getsymbol( p_module->is.plugin.handle, psz_name ); - if( !p_symbol ) + if( pf_symbol == NULL ) { /* We couldn't load the symbol */ - intf_DbgMsg( "module warning: cannot find symbol %s in module %s (%s)", - psz_name, p_module->psz_filename, module_error() ); + intf_WarnMsg( 1, "module warning: " + "cannot find symbol %s in module %s (%s)", + psz_name, p_module->is.plugin.psz_filename, + module_error() ); return( -1 ); } /* We can now try to call the symbol */ - if( p_symbol( p_module ) != 0 ) + if( pf_symbol( p_module ) != 0 ) { /* With a well-written module we shouldn't have to print an * additional error message here, but just make sure. */ intf_ErrMsg( "module error: failed calling symbol %s in module %s", - psz_name, p_module->psz_filename ); + psz_name, p_module->is.plugin.psz_filename ); return( -1 ); } /* Everything worked fine, we can return */ return( 0 ); } +#endif /* HAVE_DYNAMIC_PLUGINS */