PLUGINS: single plugin model now saves plugin filename to config file

After searching for the right plugin once, the filename will be saved to the config file under the domain 'plugin_files'. The key is the gameid and the value is the plugin file. The backup mechanism is searching plugin by plugin.

svn-id: r55061
This commit is contained in:
Yotam Barnoy 2010-12-29 15:25:21 +00:00
parent 77a6dc7046
commit 8f36a5f887
8 changed files with 135 additions and 27 deletions

View file

@ -37,7 +37,6 @@
class DCPlugin : public DynamicPlugin { class DCPlugin : public DynamicPlugin {
protected: protected:
void *_dlHandle; void *_dlHandle;
Common::String _filename;
virtual VoidFunc findSymbol(const char *symbol) { virtual VoidFunc findSymbol(const char *symbol) {
void *func = dlsym(_dlHandle, symbol); void *func = dlsym(_dlHandle, symbol);
@ -56,7 +55,7 @@ protected:
public: public:
DCPlugin(const Common::String &filename) DCPlugin(const Common::String &filename)
: _dlHandle(0), _filename(filename) {} : DynamicPlugin(filename), _dlHandle(0) {}
bool loadPlugin() { bool loadPlugin() {
assert(!_dlHandle); assert(!_dlHandle);

View file

@ -37,7 +37,12 @@ protected:
virtual VoidFunc findSymbol(const char *symbol) = 0; virtual VoidFunc findSymbol(const char *symbol) = 0;
const Common::String _filename;
public: public:
DynamicPlugin(const Common::String &filename) :
_filename(filename) {}
virtual bool loadPlugin() { virtual bool loadPlugin() {
// Validate the plugin API version // Validate the plugin API version
IntFunc verFunc = (IntFunc)findSymbol("PLUGIN_getVersion"); IntFunc verFunc = (IntFunc)findSymbol("PLUGIN_getVersion");
@ -97,6 +102,10 @@ public:
virtual void unloadPlugin() { virtual void unloadPlugin() {
delete _pluginObject; delete _pluginObject;
} }
virtual const char *getFileName() const {
return _filename.c_str();
}
}; };
#endif #endif

View file

@ -48,15 +48,14 @@ protected:
typedef const char *(*CharFunc)(); typedef const char *(*CharFunc)();
DLObject *_dlHandle; DLObject *_dlHandle;
Common::String _filename;
void *_dso_handle; void *_dso_handle;
virtual VoidFunc findSymbol(const char *symbol); virtual VoidFunc findSymbol(const char *symbol);
public: public:
ELFPlugin(const Common::String &filename) : ELFPlugin(const Common::String &filename) :
DynamicPlugin(filename),
_dlHandle(0), _dlHandle(0),
_filename(filename),
_dso_handle(0) { _dso_handle(0) {
} }

View file

@ -37,7 +37,6 @@
class POSIXPlugin : public DynamicPlugin { class POSIXPlugin : public DynamicPlugin {
protected: protected:
void *_dlHandle; void *_dlHandle;
Common::String _filename;
virtual VoidFunc findSymbol(const char *symbol) { virtual VoidFunc findSymbol(const char *symbol) {
void *func = dlsym(_dlHandle, symbol); void *func = dlsym(_dlHandle, symbol);
@ -56,7 +55,7 @@ protected:
public: public:
POSIXPlugin(const Common::String &filename) POSIXPlugin(const Common::String &filename)
: _dlHandle(0), _filename(filename) {} : DynamicPlugin(filename), _dlHandle(0) {}
bool loadPlugin() { bool loadPlugin() {
assert(!_dlHandle); assert(!_dlHandle);

View file

@ -36,7 +36,6 @@
class SDLPlugin : public DynamicPlugin { class SDLPlugin : public DynamicPlugin {
protected: protected:
void *_dlHandle; void *_dlHandle;
Common::String _filename;
virtual VoidFunc findSymbol(const char *symbol) { virtual VoidFunc findSymbol(const char *symbol) {
void *func = SDL_LoadFunction(_dlHandle, symbol); void *func = SDL_LoadFunction(_dlHandle, symbol);
@ -55,7 +54,7 @@ protected:
public: public:
SDLPlugin(const Common::String &filename) SDLPlugin(const Common::String &filename)
: _dlHandle(0), _filename(filename) {} : DynamicPlugin(filename), _dlHandle(0) {}
bool loadPlugin() { bool loadPlugin() {
assert(!_dlHandle); assert(!_dlHandle);

View file

@ -51,7 +51,6 @@ private:
protected: protected:
void *_dlHandle; void *_dlHandle;
Common::String _filename;
virtual VoidFunc findSymbol(const char *symbol) { virtual VoidFunc findSymbol(const char *symbol) {
#ifndef _WIN32_WCE #ifndef _WIN32_WCE
@ -67,7 +66,7 @@ protected:
public: public:
Win32Plugin(const Common::String &filename) Win32Plugin(const Common::String &filename)
: _dlHandle(0), _filename(filename) {} : DynamicPlugin(filename), _dlHandle(0) {}
bool loadPlugin() { bool loadPlugin() {
assert(!_dlHandle); assert(!_dlHandle);

View file

@ -335,16 +335,15 @@ void PluginManager::addPluginProvider(PluginProvider *pp) {
_providers.push_back(pp); _providers.push_back(pp);
} }
// /**
// This should only be run once * This should only be called once by main()
**/
void PluginManagerUncached::init() { void PluginManagerUncached::init() {
unloadAllPlugins(); unloadAllPlugins();
_allEnginePlugins.clear(); _allEnginePlugins.clear();
// We need to resize our pluginsInMem list to prevent fragmentation // Resize our pluginsInMem list to prevent fragmentation
// Otherwise, as soon as we add our 1 engine plugin (which is all we'll have in memory at a time) _pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2);
// We'll get an allocation in memory that will never go away
_pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2); // more than we need
for (ProviderList::iterator pp = _providers.begin(); for (ProviderList::iterator pp = _providers.begin();
pp != _providers.end(); pp != _providers.end();
@ -371,6 +370,63 @@ void PluginManagerUncached::init() {
} }
} }
/**
* Try to load the plugin by searching in the ConfigManager for a matching
* gameId under the domain 'plugin_files'.
**/
bool PluginManagerUncached::loadPluginFromGameId(const Common::String &gameId) {
Common::ConfigManager::Domain *domain = ConfMan.getDomain("plugin_files");
if (domain) {
if (domain->contains(gameId)) {
Common::String filename = (*domain)[gameId];
if (loadPluginByFileName(filename)) {
return true;
}
}
}
return false;
}
/**
* Load a plugin with a filename taken from ConfigManager.
**/
bool PluginManagerUncached::loadPluginByFileName(const Common::String &filename) {
if (filename.empty())
return false;
unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
PluginList::iterator i;
for (i = _allEnginePlugins.begin(); i != _allEnginePlugins.end(); ++i) {
if (Common::String((*i)->getFileName()) == filename && (*i)->loadPlugin()) {
addToPluginsInMemList(*i);
_currentPlugin = i;
return true;
}
}
return false;
}
/**
* Update the config manager with a plugin file name that we found can handle
* the game.
**/
void PluginManagerUncached::updateConfigWithFileName(const Common::String &gameId) {
// Check if we have a filename for the current plugin
if ((*_currentPlugin)->getFileName()) {
if (!ConfMan.hasMiscDomain("plugin_files"))
ConfMan.addMiscDomain("plugin_files");
Common::ConfigManager::Domain *domain = ConfMan.getDomain("plugin_files");
assert(domain);
(*domain)[gameId] = (*_currentPlugin)->getFileName();
ConfMan.flushToDisk();
}
}
void PluginManagerUncached::loadFirstPlugin() { void PluginManagerUncached::loadFirstPlugin() {
unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
@ -395,6 +451,10 @@ bool PluginManagerUncached::loadNextPlugin() {
return false; // no more in list return false; // no more in list
} }
/**
* Used by only the cached plugin manager. The uncached manager can only have
* one plugin in memory at a time.
**/
void PluginManager::loadAllPlugins() { void PluginManager::loadAllPlugins() {
for (ProviderList::iterator pp = _providers.begin(); for (ProviderList::iterator pp = _providers.begin();
pp != _providers.end(); pp != _providers.end();
@ -426,6 +486,9 @@ void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin, b
} }
} }
/*
* Used only by the cached plugin manager since it deletes the plugin.
*/
bool PluginManager::tryLoadPlugin(Plugin *plugin) { bool PluginManager::tryLoadPlugin(Plugin *plugin) {
assert(plugin); assert(plugin);
// Try to load the plugin // Try to load the plugin
@ -439,6 +502,9 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) {
} }
} }
/**
* Add to the list of plugins loaded in memory.
*/
void PluginManager::addToPluginsInMemList(Plugin *plugin) { void PluginManager::addToPluginsInMemList(Plugin *plugin) {
bool found = false; bool found = false;
// The plugin is valid, see if it provides the same module as an // The plugin is valid, see if it provides the same module as an
@ -468,16 +534,35 @@ void PluginManager::addToPluginsInMemList(Plugin *plugin) {
DECLARE_SINGLETON(EngineManager); DECLARE_SINGLETON(EngineManager);
/**
* This function works for both cached and uncached PluginManagers.
* For the cached version, most of the logic here will short circuit.
*
* For the uncached version, we first try to find the plugin using the gameId
* and only if we can't find it there, we loop through the plugins.
**/
GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const { GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const {
GameDescriptor result; GameDescriptor result;
PluginManager::instance().loadFirstPlugin(); // first look for the game using the gameId
if (PluginMan.loadPluginFromGameId(gameName)) {
result = findGameInLoadedPlugins(gameName, plugin);
if (!result.gameid().empty()) {
return result;
}
}
// We failed to find it using the gameid. Scan the list of plugins
PluginMan.loadFirstPlugin();
do { do {
result = findGameInLoadedPlugins(gameName, plugin); result = findGameInLoadedPlugins(gameName, plugin);
if (!result.gameid().empty()) { if (!result.gameid().empty()) {
// Update with new plugin file name
PluginMan.updateConfigWithFileName(gameName);
break; break;
} }
} while (PluginManager::instance().loadNextPlugin()); } while (PluginMan.loadNextPlugin());
return result; return result;
} }

View file

@ -153,10 +153,10 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX];
/** /**
* Abstract base class for the plugin objects which handle plugins * Abstract base class for the plugin objects which handle plugins
* instantiation. Subclasses for this may be used for engine plugins * instantiation. Subclasses for this may be used for engine plugins and other
* and other types of plugins. * types of plugins. An existing PluginObject refers to an executable file
* * loaded in memory and ready to run. The plugin, on the other hand, is just
* FIXME: This class needs better documentation, esp. how it differs from class Plugin * a handle to the file/object, whether it's loaded in memory or not.
*/ */
class PluginObject { class PluginObject {
public: public:
@ -169,9 +169,8 @@ public:
/** /**
* Abstract base class for the plugin system. * Abstract base class for the plugin system.
* Subclasses for this can be used to wrap both static and dynamic * Subclasses for this can be used to wrap both static and dynamic
* plugins. * plugins. This class refers to a plugin which may or may not be loaded in
* * memory.
* FIXME: This class needs better documentation, esp. how it differs from class PluginObject
*/ */
class Plugin { class Plugin {
protected: protected:
@ -189,8 +188,19 @@ public:
virtual bool loadPlugin() = 0; // TODO: Rename to load() ? virtual bool loadPlugin() = 0; // TODO: Rename to load() ?
virtual void unloadPlugin() = 0; // TODO: Rename to unload() ? virtual void unloadPlugin() = 0; // TODO: Rename to unload() ?
/**
* The following functions query information from the plugin object once
* it's loaded into memory.
**/
PluginType getType() const; PluginType getType() const;
const char *getName() const; const char *getName() const;
/**
* The getFileName() function gets the name of the plugin file for those
* plugins that have files (ie. not static). It doesn't require the plugin
* object to be loaded into memory, unlike getName()
**/
virtual const char *getFileName() const { return 0; }
}; };
/** List of Plugin instances. */ /** List of Plugin instances. */
@ -294,6 +304,8 @@ protected:
#endif // DYNAMIC_MODULES #endif // DYNAMIC_MODULES
#define PluginMan PluginManager::instance()
/** /**
* Singleton class which manages all plugins, including loading them, * Singleton class which manages all plugins, including loading them,
* managing all Plugin class instances, and unloading them. * managing all Plugin class instances, and unloading them.
@ -319,10 +331,14 @@ public:
void addPluginProvider(PluginProvider *pp); void addPluginProvider(PluginProvider *pp);
// Functions used by the uncached PluginManager
virtual void init() {} virtual void init() {}
virtual void loadFirstPlugin() {} virtual void loadFirstPlugin() {}
virtual bool loadNextPlugin() { return false; } virtual bool loadNextPlugin() { return false; }
virtual bool loadPluginFromGameId(const Common::String &gameId) { return false; }
virtual void updateConfigWithFileName(const Common::String &gameId) {}
// Functions used only by the cached PluginManager
virtual void loadAllPlugins(); virtual void loadAllPlugins();
void unloadAllPlugins(); void unloadAllPlugins();
@ -342,11 +358,14 @@ protected:
PluginList::iterator _currentPlugin; PluginList::iterator _currentPlugin;
PluginManagerUncached() {} PluginManagerUncached() {}
bool loadPluginByFileName(const Common::String &filename);
public: public:
virtual void init(); virtual void init();
virtual void loadFirstPlugin(); virtual void loadFirstPlugin();
virtual bool loadNextPlugin(); virtual bool loadNextPlugin();
virtual bool loadPluginFromGameId(const Common::String &gameId);
virtual void updateConfigWithFileName(const Common::String &gameId);
virtual void loadAllPlugins() {} // we don't allow this virtual void loadAllPlugins() {} // we don't allow this
}; };