[Scummvm-cvs-logs] SF.net SVN: scummvm:[54097] scummvm/trunk

bluddy at users.sourceforge.net bluddy at users.sourceforge.net
Fri Nov 5 14:24:58 CET 2010


Revision: 54097
          http://scummvm.svn.sourceforge.net/scummvm/?rev=54097&view=rev
Author:   bluddy
Date:     2010-11-05 13:24:57 +0000 (Fri, 05 Nov 2010)

Log Message:
-----------
PLUGINS: improved one-at-a-time plugin code

I reduced memory fragmentation using 2 principles: Plugins should be loaded for as little time as possible, and long lasting memory allocations should be allocated before plugins are loaded. There might still be a little fragmentation left.
Note that command line settings that require plugins to be loaded don't work yet, but they didn't work (properly) before either.

Modified Paths:
--------------
    scummvm/trunk/base/main.cpp
    scummvm/trunk/base/plugins.cpp
    scummvm/trunk/base/plugins.h
    scummvm/trunk/engines/metaengine.h
    scummvm/trunk/gui/launcher.cpp

Modified: scummvm/trunk/base/main.cpp
===================================================================
--- scummvm/trunk/base/main.cpp	2010-11-05 13:19:21 UTC (rev 54096)
+++ scummvm/trunk/base/main.cpp	2010-11-05 13:24:57 UTC (rev 54097)
@@ -107,7 +107,7 @@
 	printf("%s", "  Looking for a plugin supporting this gameid... ");
 
 #if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
-	GameDescriptor game = EngineMan.findGameOnePlugAtATime(gameid, &plugin);
+	GameDescriptor game = EngineMan.findGameOnePluginAtATime(gameid, &plugin);
 #else
  	GameDescriptor game = EngineMan.findGame(gameid, &plugin);
 #endif
@@ -216,6 +216,11 @@
 	// Run the engine
 	Common::Error result = engine->run();
 
+#if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
+	// do our best to prevent fragmentation by unloading as soon as we can
+	PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
+#endif	
+	
 	// Inform backend that the engine finished
 	system.engineDone();
 
@@ -343,7 +348,7 @@
 
 #if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
 	// Only load non-engine plugins and first engine plugin initially in this case.
-	PluginManager::instance().loadFirstPlugin();
+	PluginManager::instance().loadNonEnginePluginsAndEnumerate();
 #else
  	// Load the plugins.
  	PluginManager::instance().loadPlugins();
@@ -363,6 +368,7 @@
 	// config file and the plugins have been loaded.
 	Common::Error res;
 
+	// TODO: deal with settings that require plugins to be loaded
 	if ((res = Base::processSettings(command, settings)) != Common::kArgumentNotProcessed)
 		return res;
 
@@ -431,9 +437,7 @@
 
 			// PluginManager::instance().unloadPlugins();
 
-#if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
-			PluginManager::instance().loadFirstPlugin();
-#else
+#if !defined(ONE_PLUGIN_AT_A_TIME)
 			PluginManager::instance().loadPlugins();
 #endif
 		} else {

Modified: scummvm/trunk/base/plugins.cpp
===================================================================
--- scummvm/trunk/base/plugins.cpp	2010-11-05 13:19:21 UTC (rev 54096)
+++ scummvm/trunk/base/plugins.cpp	2010-11-05 13:24:57 UTC (rev 54097)
@@ -305,7 +305,6 @@
 PluginManager::PluginManager() {
 	// Always add the static plugin provider.
 	addPluginProvider(new StaticPluginProvider());
-	_skipStaticPlugs = false;
 }
 
 PluginManager::~PluginManager() {
@@ -324,58 +323,60 @@
 	_providers.push_back(pp);
 }
 
-void PluginManager::loadFirstPlugin() { //TODO: rename? It's not quite clear that this loads all non-engine plugins and first engine plugin.
-	unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL);
-	_allPlugs.clear();
+//
+// This should only be run once
+void PluginManager::loadNonEnginePluginsAndEnumerate() {
+	unloadPlugins();
+	_allEnginePlugins.clear();
+	
+	// We need to 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)
+	// 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();
 	                            pp != _providers.end();
 	                            ++pp) {
-		if ((_skipStaticPlugs && (*pp)->isFilePluginProvider()) || !_skipStaticPlugs) {
-			PluginList pl((*pp)->getPlugins());
-			for (PluginList::iterator p = pl.begin(); p != pl.end(); ++p) {
-				_allPlugs.push_back(*p);
-			}
-		}
-	}
+		PluginList pl((*pp)->getPlugins());
+		for (PluginList::iterator p = pl.begin(); p != pl.end(); ++p) {
+			// To find out which are engine plugins, we have to load them. This is inefficient
+			// Hopefully another way can be found (e.g. if the music plugins are all static, 
+			// we can use only the static provider
+			if ((*p)->loadPlugin()) {
+				if ((*p)->getType() == PLUGIN_TYPE_ENGINE) {
+					(*p)->unloadPlugin();				// to prevent fragmentation
+					_allEnginePlugins.push_back(*p);
+				} else {	// add non-engine plugins to the 'in-memory' list
+							// these won't ever get unloaded (in this implementation)
+					addToPluginsInMemList(*p);			
+				}
+			}	
+ 		}
+ 	}
+}
 
-	_nonEnginePlugs = 0;
-	_skipStaticPlugs = true; //Only need to load static plugins once.
+void PluginManager::loadFirstPlugin() { 
+	unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
 
-	_currentPlugin = _allPlugs.begin();
-
-	if (_allPlugs.empty()) {
-		return; //return here if somehow there are no plugins to load.
-	}
-
-	//this loop is for loading all non-engine plugins and the first engine plugin.
-	for (; _currentPlugin != _allPlugs.end(); ++_currentPlugin) {
-		if (!tryLoadPlugin(*_currentPlugin))
-			continue;
-
-		// TODO: This assumes all non-engine plugins will precede the first engine plugin!
-		if ((*_currentPlugin)->getType() == PLUGIN_TYPE_ENGINE)
+	// let's try to find one we can load
+	for (_currentPlugin = _allEnginePlugins.begin(); _currentPlugin != _allEnginePlugins.end(); ++_currentPlugin) {
+		if ((*_currentPlugin)->loadPlugin()) {
+			addToPluginsInMemList(*_currentPlugin);
 			break;
-
-		_nonEnginePlugs++;
+		}
 	}
-
-	return;
 }
 
 bool PluginManager::loadNextPlugin() {
-	if (_nonEnginePlugs == _allPlugs.size())
-		return false; //There are no Engine Plugins in this case.
+	unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
 
-	// To ensure only one engine plugin is loaded at a time, we unload all engine plugins before trying to load a new one.
-	unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL);
-
-	++_currentPlugin;
-	for (; _currentPlugin != _allPlugs.end(); ++_currentPlugin)
-		if (tryLoadPlugin(*_currentPlugin))
+	for (++_currentPlugin; _currentPlugin != _allEnginePlugins.end(); ++_currentPlugin) {
+		if ((*_currentPlugin)->loadPlugin()) {
+			addToPluginsInMemList(*_currentPlugin);
 			return true;
-
-	loadFirstPlugin();
-	return false;
+		}
+	}
+	return false;	// no more in list
 }
 
 void PluginManager::loadPlugins() {
@@ -392,19 +393,20 @@
 		unloadPluginsExcept((PluginType)i, NULL);
 }
 
-void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin) {
+void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin, bool deletePlugin /*=true*/) {
 	Plugin *found = NULL;
-	for (PluginList::iterator p = _plugins[type].begin(); p != _plugins[type].end(); ++p) {
+	for (PluginList::iterator p = _pluginsInMem[type].begin(); p != _pluginsInMem[type].end(); ++p) {
 		if (*p == plugin) {
 			found = *p;
 		} else {
 			(*p)->unloadPlugin();
-			delete *p;
+			if (deletePlugin)
+				delete *p;
 		}
 	}
-	_plugins[type].clear();
+	_pluginsInMem[type].clear();
 	if (found != NULL) {
-		_plugins[type].push_back(found);
+		_pluginsInMem[type].push_back(found);
 	}
 }
 
@@ -412,26 +414,7 @@
 	assert(plugin);
 	// Try to load the plugin
 	if (plugin->loadPlugin()) {
-		// The plugin is valid, see if it provides the same module as an
-		// already loaded one and should replace it.
-		bool found = false;
-		PluginList::iterator pl = _plugins[plugin->getType()].begin();
-		while (!found && pl != _plugins[plugin->getType()].end()) {
-			if (!strcmp(plugin->getName(), (*pl)->getName())) {
-				// Found a duplicated module. Replace the old one.
-				found = true;
-				delete *pl;
-				*pl = plugin;
-				debug(1, "Replaced the duplicated plugin: '%s'", plugin->getName());
-			}
-			pl++;
-		}
-
-		if (!found) {
-			// If it provides a new module, just add it to the list of known plugins.
-			_plugins[plugin->getType()].push_back(plugin);
-		}
-
+		addToPluginsInMemList(plugin);
 		return true;
 	} else {
 		// Failed to load the plugin
@@ -440,15 +423,38 @@
 	}
 }
 
+void PluginManager::addToPluginsInMemList(Plugin *plugin) {
+	bool found = false;
+	// The plugin is valid, see if it provides the same module as an
+	// already loaded one and should replace it.
+		
+	PluginList::iterator pl = _pluginsInMem[plugin->getType()].begin();
+	while (!found && pl != _pluginsInMem[plugin->getType()].end()) {
+		if (!strcmp(plugin->getName(), (*pl)->getName())) {
+			// Found a duplicated module. Replace the old one.
+			found = true;
+			delete *pl;
+			*pl = plugin;
+			debug(1, "Replaced the duplicated plugin: '%s'", plugin->getName());
+		}
+		pl++;
+	}
+
+	if (!found) {
+		// If it provides a new module, just add it to the list of known plugins in memory.
+		_pluginsInMem[plugin->getType()].push_back(plugin);
+	}
+}
+
 // Engine plugins
 
 #include "engines/metaengine.h"
 
 DECLARE_SINGLETON(EngineManager)
 
-GameDescriptor EngineManager::findGameOnePlugAtATime(const Common::String &gameName, const EnginePlugin **plugin) const {
+GameDescriptor EngineManager::findGameOnePluginAtATime(const Common::String &gameName, const EnginePlugin **plugin) const {
 	GameDescriptor result;
-	//PluginManager::instance().loadFirstPlugin();
+	PluginManager::instance().loadFirstPlugin();
 	do {
 		result = findGame(gameName, plugin); 
 		if (!result.gameid().empty()) {
@@ -468,14 +474,14 @@
 
 	EnginePlugin::List::const_iterator iter;
 	
-		for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
-			result = (**iter)->findGame(gameName.c_str());
-			if (!result.gameid().empty()) {
-				if (plugin)
-					*plugin = *iter;
-				return result;
-			}
+	for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
+		result = (**iter)->findGame(gameName.c_str());
+		if (!result.gameid().empty()) {
+			if (plugin)
+				*plugin = *iter;
+			return result;
 		}
+	}
 	return result;
 }
 
@@ -484,6 +490,7 @@
 	EnginePlugin::List plugins;
 	EnginePlugin::List::const_iterator iter;
 #if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
+	PluginManager::instance().loadFirstPlugin();
 	do {
 #endif
 		plugins = getPlugins();

Modified: scummvm/trunk/base/plugins.h
===================================================================
--- scummvm/trunk/base/plugins.h	2010-11-05 13:19:21 UTC (rev 54096)
+++ scummvm/trunk/base/plugins.h	2010-11-05 13:24:57 UTC (rev 54097)
@@ -301,17 +301,14 @@
 class PluginManager : public Common::Singleton<PluginManager> {
 	typedef Common::Array<PluginProvider *> ProviderList;
 private:
-	PluginList _plugins[PLUGIN_TYPE_MAX];
+	PluginList _pluginsInMem[PLUGIN_TYPE_MAX];
 	ProviderList _providers;
 
-	PluginList _allPlugs;
+	PluginList _allEnginePlugins;
 	PluginList::iterator _currentPlugin;
 
-	bool _skipStaticPlugs;
-
-	uint _nonEnginePlugs;
-
 	bool tryLoadPlugin(Plugin *plugin);
+	void addToPluginsInMemList(Plugin *plugin);
 	
 	friend class Common::Singleton<SingletonBaseType>;
 	PluginManager();
@@ -321,14 +318,15 @@
 
 	void addPluginProvider(PluginProvider *pp);
 
+	void loadNonEnginePluginsAndEnumerate();	
 	void loadFirstPlugin();
 	bool loadNextPlugin();
 	
 	void loadPlugins();
 	void unloadPlugins();
-	void unloadPluginsExcept(PluginType type, const Plugin *plugin);
+	void unloadPluginsExcept(PluginType type, const Plugin *plugin, bool deletePlugin = true);
 
-	const PluginList &getPlugins(PluginType t) { return _plugins[t]; }
+	const PluginList &getPlugins(PluginType t) { return _pluginsInMem[t]; }
 };
 
 #endif

Modified: scummvm/trunk/engines/metaengine.h
===================================================================
--- scummvm/trunk/engines/metaengine.h	2010-11-05 13:19:21 UTC (rev 54096)
+++ scummvm/trunk/engines/metaengine.h	2010-11-05 13:24:57 UTC (rev 54097)
@@ -231,7 +231,7 @@
 	friend class Common::Singleton<SingletonBaseType>;
 
 public:
-	GameDescriptor findGameOnePlugAtATime(const Common::String &gameName, const EnginePlugin **plugin = NULL) const;
+	GameDescriptor findGameOnePluginAtATime(const Common::String &gameName, const EnginePlugin **plugin = NULL) const;
 	GameDescriptor findGame(const Common::String &gameName, const EnginePlugin **plugin = NULL) const;
 	GameList detectGames(const Common::FSList &fslist) const;
 	const EnginePlugin::List &getPlugins() const;

Modified: scummvm/trunk/gui/launcher.cpp
===================================================================
--- scummvm/trunk/gui/launcher.cpp	2010-11-05 13:19:21 UTC (rev 54096)
+++ scummvm/trunk/gui/launcher.cpp	2010-11-05 13:24:57 UTC (rev 54097)
@@ -925,7 +925,7 @@
 	const EnginePlugin *plugin = 0;
 	
 #if defined(ONE_PLUGIN_AT_A_TIME) && defined(DYNAMIC_MODULES)
-	EngineMan.findGameOnePlugAtATime(gameId, &plugin);
+	EngineMan.findGameOnePluginAtATime(gameId, &plugin);
 #else
 	EngineMan.findGame(gameId, &plugin);
 #endif


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list