/*****************************************************************************
- * 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.20 2001/04/06 18:18:10 massiot Exp $
+ * $Id: modules.c,v 1.28 2001/05/01 04:18:18 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Ethan C. Baldridge <BaldridgeE@cadmus.com>
#include <dirent.h>
#if defined(HAVE_DLFCN_H) /* Linux, BSD, Hurd */
-#include <dlfcn.h> /* dlopen(), dlsym(), dlclose() */
-
+# include <dlfcn.h> /* dlopen(), dlsym(), dlclose() */
+# define HAVE_DYNAMIC_PLUGINS
#elif defined(HAVE_IMAGE_H) /* BeOS */
-#include <image.h>
-
+# include <image.h>
+# 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
-#include "common.h"
-#include "threads.h"
-
#ifdef SYS_DARWIN1_3
-#include <sys/param.h> /* for MAXPATHLEN */
-#include "main.h"
-extern main_t *p_main;
+# include "darwin_specific.h"
#endif
+#include "common.h"
+#include "threads.h"
+
#include "intf_msg.h"
#include "modules.h"
-#include "modules_core.h"
+#ifdef HAVE_DYNAMIC_PLUGINS
+# include "modules_core.h"
+#endif
+#include "modules_builtin.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 );
-
-/*****************************************************************************
- * module_CreateBank: create the module bank.
- *****************************************************************************
- * This function creates a module bank structure.
- *****************************************************************************/
-module_bank_t * module_CreateBank( void )
-{
- module_bank_t * p_bank;
-
- p_bank = malloc( sizeof( module_bank_t ) );
-
- return( 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
/*****************************************************************************
* 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( )
{
+#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_vlcpath = beos_GetProgramPath();
+#if defined( SYS_BEOS ) || defined( SYS_DARWIN1_3 )
+ char * psz_vlcpath = system_GetProgramPath();
int i_vlclen = strlen( psz_vlcpath );
boolean_t b_notinroot;
-#elif defined SYS_DARWIN1_3
- static char once = 0;
- static char app_path[ MAXPATHLEN ];
- // HACK TO CUT OUT trailing 'vlc'
- int i_pathlen = strlen( p_main->ppsz_argv[0] ) - 3;
#endif
DIR * dir;
struct dirent * file;
+#endif /* HAVE_DYNAMIC_PLUGINS */
p_bank->first = NULL;
vlc_mutex_init( &p_bank->lock );
- intf_WarnMsg( 1, "module: module bank initialized" );
+ intf_WarnMsg( 2, "module: checking built-in modules" );
-#ifdef SYS_DARWIN1_3
- if ( !once )
- {
- once = 1;
- strncpy( app_path, p_main->ppsz_argv[ 0 ], i_pathlen );
- intf_ErrMsg( "%s", p_main->ppsz_argv[ 0 ] );
- strcat( app_path, "lib" );
- path[ 3 ] = app_path ;
- intf_ErrMsg( "%s", path[ 3 ] );
- }
-#endif
+ ALLOCATE_ALL_BUILTINS();
+
+#ifdef HAVE_DYNAMIC_PLUGINS
+ intf_WarnMsg( 2, "module: checking plugin modules" );
for( ; *ppsz_path != NULL ; ppsz_path++ )
{
/* Store strlen(*ppsz_path) for later use. */
int i_dirlen = strlen( *ppsz_path );
-#ifdef SYS_BEOS
+#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 */
psz_fullpath = *ppsz_path;
}
- intf_WarnMsgImm( 2, "module: browsing %s", psz_fullpath );
+ intf_WarnMsgImm( 3, "module: browsing `%s'", psz_fullpath );
if( (dir = opendir( psz_fullpath )) )
{
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 );
closedir( dir );
}
-#ifdef SYS_BEOS
+#if defined( SYS_BEOS ) || defined( SYS_DARWIN1_3 )
if( b_notinroot )
{
free( psz_fullpath );
}
#endif
}
+#endif /* HAVE_DYNAMIC_PLUGINS */
+
+ intf_WarnMsg( 1, "module: module bank initialized" );
return;
}
/*****************************************************************************
- * module_DestroyBank: destroy the module bank.
+ * module_EndBank: destroy the module bank.
*****************************************************************************
- * This function unloads all unused dynamic modules and removes the module
+ * This function unloads all unused plugin modules and removes the module
* bank in case of success.
*****************************************************************************/
-void module_DestroyBank( module_bank_t * p_bank )
+void module_EndBank( )
{
module_t * p_next;
while( p_bank->first != NULL )
{
- if( FreeModule( p_bank, p_bank->first ) )
+ if( DeleteModule( p_bank->first ) )
{
/* Module deletion failed */
intf_ErrMsg( "module error: `%s' can't be removed. trying harder.",
/* Destroy the lock */
vlc_mutex_destroy( &p_bank->lock );
-
- /* We can free the module bank */
- free( p_bank );
return;
}
/*****************************************************************************
* 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( )
{
intf_ErrMsg( "FIXME: module_ResetBank unimplemented" );
return;
* 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( )
{
+#ifdef HAVE_DYNAMIC_PLUGINS
module_t * p_module;
/* We take the global lock */
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 )
}
else
{
- intf_WarnMsg( 1, "module: hiding unused module `%s'",
+ intf_WarnMsg( 3, "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 );
+#endif /* HAVE_DYNAMIC_PLUGINS */
return;
}
*****************************************************************************
* 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;
}
}
- /* We release the global lock */
+ /* We can release the global lock, module refcount was incremented */
vlc_mutex_unlock( &p_bank->lock );
if( p_bestmodule != NULL )
{
- intf_WarnMsg( 1, "module: locking module `%s'",
+ intf_WarnMsg( 3, "module: locking module `%s'",
p_bestmodule->psz_name );
}
* 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 );
* so there is no need to check the return value. */
UnlockModule( p_module );
- intf_WarnMsg( 1, "module: unlocking module `%s'", p_module->psz_name );
+ intf_WarnMsg( 3, "module: unlocking module `%s'", p_module->psz_name );
/* We release the global lock */
vlc_mutex_unlock( &p_bank->lock );
* 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;
/* Try to dynamically load the module. */
if( module_load( psz_filename, &handle ) )
{
- /* The dynamic module couldn't be opened */
- intf_WarnMsgImm( 1, "module warning: cannot open %s (%s)",
+ /* The plugin module couldn't be opened */
+ intf_WarnMsgImm( 3, "module warning: cannot open %s (%s)",
psz_filename, module_error() );
return( -1 );
}
}
/* 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;
/* Initialize the module : fill p_module->psz_name, etc. */
if( CallSymbol( p_module, "InitModule" ) != 0 )
/* 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 );
p_bank->first = p_module;
/* Immediate message so that a slow module doesn't make the user wait */
- intf_WarnMsgImm( 1, "module: dynamic module `%s', %s",
+ 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_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_bank->first != NULL )
+ {
+ p_bank->first->prev = p_module;
+ }
+ p_module->next = p_bank->first;
+ p_module->prev = NULL;
+ p_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
" 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 )
}
}
}
+#endif
/* Unlink the module from the linked list. */
if( p_module == p_bank->first )
}
/* 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 );
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 );
}
{
/* 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 );
}
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.
*****************************************************************************
symbol_t * p_symbol;
/* Try to resolve the symbol */
- p_symbol = module_getsymbol( p_module->handle, psz_name );
+ p_symbol = module_getsymbol( p_module->is.plugin.handle, psz_name );
if( !p_symbol )
{
/* We couldn't load the symbol */
- intf_WarnMsg( 1, "module warning: "
+ intf_WarnMsg( 3, "module warning: "
"cannot find symbol %s in module %s (%s)",
- psz_name, p_module->psz_filename, module_error() );
+ psz_name, p_module->is.plugin.psz_filename,
+ module_error() );
return( -1 );
}
/* 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 */