+/*****************************************************************************
+ * 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 built-in module should always have a refcount >= 0 ! */
+ intf_ErrMsg( "module error: built-in module `%s' has refcount %i",
+ p_module->psz_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. */
+ 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->is.plugin.psz_filename,
+ &p_module->is.plugin.handle ) )
+ {
+ /* The plugin module couldn't be opened */
+ intf_ErrMsg( "module error: cannot open %s (%s)",
+ p_module->is.plugin.psz_filename, module_error() );
+ 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. */
+
+ /* Activate the module : fill the capability structure, etc. */
+ if( CallSymbol( p_module, "ActivateModule" ) != 0 )
+ {
+ /* We couldn't call ActivateModule() -- looks nasty, but
+ * we can't do much about it. Just try to unload module. */
+ 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 );
+}
+
+/*****************************************************************************
+ * 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. */
+ intf_ErrMsg( "module error: trying to call module_Unneed() on `%s'"
+ " which isn't even in use", p_module->psz_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 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 );
+}
+