summaryrefslogtreecommitdiff
path: root/library/PluginManager.cpp
diff options
context:
space:
mode:
authorPetr Mrázek2011-07-18 16:22:49 +0200
committerPetr Mrázek2011-07-18 16:22:49 +0200
commit84f74bc091a9e1fd9b9046ff4bde986ead4f49b0 (patch)
tree44ecd189a37d20b6bef8ccaafb39158a201b2232 /library/PluginManager.cpp
parentfdb5397a1da66f99e28542e61c3dda99efa7effa (diff)
downloaddfhack-84f74bc091a9e1fd9b9046ff4bde986ead4f49b0.tar.gz
dfhack-84f74bc091a9e1fd9b9046ff4bde986ead4f49b0.tar.bz2
dfhack-84f74bc091a9e1fd9b9046ff4bde986ead4f49b0.tar.xz
Added plugin loading/unloading/reloading. Many locks. Too many damn locks.
Diffstat (limited to 'library/PluginManager.cpp')
-rw-r--r--library/PluginManager.cpp274
1 files changed, 231 insertions, 43 deletions
diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp
index 1d34d8ad..4caff02e 100644
--- a/library/PluginManager.cpp
+++ b/library/PluginManager.cpp
@@ -67,71 +67,241 @@ bool hasEnding (std::string const &fullString, std::string const &ending)
return false;
}
}
-
-Plugin::Plugin(Core * core, const std::string & file)
+struct Plugin::RefLock
+{
+ RefLock()
+ {
+ refcount = 0;
+ wakeup = SDL_CreateCond();
+ mut = SDL_CreateMutex();
+ }
+ ~RefLock()
+ {
+ SDL_DestroyCond(wakeup);
+ SDL_DestroyMutex(mut);
+ }
+ void lock()
+ {
+ SDL_mutexP(mut);
+ }
+ void unlock()
+ {
+ SDL_mutexV(mut);
+ }
+ void lock_add()
+ {
+ SDL_mutexP(mut);
+ refcount ++;
+ SDL_mutexV(mut);
+ }
+ void lock_sub()
+ {
+ SDL_mutexP(mut);
+ refcount --;
+ SDL_CondSignal(wakeup);
+ SDL_mutexV(mut);
+ }
+ void operator++()
+ {
+ refcount ++;
+ }
+ void operator--()
+ {
+ refcount --;
+ SDL_CondSignal(wakeup);
+ }
+ void wait()
+ {
+ while(refcount)
+ {
+ SDL_CondWait(wakeup, mut);
+ }
+ }
+ SDL::Cond * wakeup;
+ SDL::Mutex * mut;
+ int refcount;
+};
+Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _filename, PluginManager * pm)
{
- filename = file;
+ filename = filepath;
+ parent = pm;
+ name.reserve(_filename.size());
+ for(int i = 0; i < _filename.size();i++)
+ {
+ char ch = _filename[i];
+ if(ch == '.')
+ break;
+ name.append(1,ch);
+ }
Console & con = core->con;
plugin_lib = 0;
plugin_init = 0;
plugin_shutdown = 0;
plugin_status = 0;
plugin_onupdate = 0;
- loaded = false;
- DFLibrary * plug = OpenPlugin(file.c_str());
+ state = PS_UNLOADED;
+ access = new RefLock();
+}
+
+Plugin::~Plugin()
+{
+ if(state == PS_LOADED)
+ {
+ unload();
+ }
+ delete access;
+}
+
+bool Plugin::load()
+{
+ access->lock();
+ if(state == PS_BROKEN)
+ {
+ access->unlock();
+ return false;
+ }
+ else if(state == PS_LOADED)
+ {
+ access->unlock();
+ return true;
+ }
+ Core & c = Core::getInstance();
+ Console & con = c.con;
+ DFLibrary * plug = OpenPlugin(filename.c_str());
if(!plug)
{
- con.print("Can't load plugin %s\n", filename.c_str());
- return;
+ con.printerr("Can't load plugin %s\n", filename.c_str());
+ state = PS_BROKEN;
+ access->unlock();
+ return false;
}
const char * (*_PlugName)() =(const char * (*)()) LookupPlugin(plug, "plugin_name");
if(!_PlugName)
{
- con.print("Plugin %s has no name.\n", filename.c_str());
+ con.printerr("Plugin %s has no name.\n", filename.c_str());
ClosePlugin(plug);
- return;
+ state = PS_BROKEN;
+ access->unlock();
+ return false;
}
plugin_init = (command_result (*)(Core *, std::vector <PluginCommand> &)) LookupPlugin(plug, "plugin_init");
if(!plugin_init)
{
- con.print("Plugin %s has no init function.\n", filename.c_str());
+ con.printerr("Plugin %s has no init function.\n", filename.c_str());
ClosePlugin(plug);
- return;
+ state = PS_BROKEN;
+ access->unlock();
+ return false;
}
plugin_status = (command_result (*)(Core *, std::string &)) LookupPlugin(plug, "plugin_status");
plugin_onupdate = (command_result (*)(Core *)) LookupPlugin(plug, "plugin_onupdate");
plugin_shutdown = (command_result (*)(Core *)) LookupPlugin(plug, "plugin_shutdown");
name = _PlugName();
plugin_lib = plug;
- loaded = true;
- //dfout << "Found plugin " << name << endl;
- if(plugin_init(core,commands) == CR_OK)
+ if(plugin_init(&c,commands) == CR_OK)
+ {
+ state = PS_LOADED;
+ parent->registerCommands(this);
+ access->unlock();
+ return true;
+ }
+ else
{
- /*
- for(int i = 0; i < commands.size();i++)
+ con.printerr("Plugin %s has failed to initialize properly.\n", filename.c_str());
+ ClosePlugin(plugin_lib);
+ state = PS_BROKEN;
+ access->unlock();
+ return false;
+ }
+ // not reachable
+}
+
+bool Plugin::unload()
+{
+ Core & c = Core::getInstance();
+ Console & con = c.con;
+ // get the mutex
+ access->lock();
+ // if we are actually loaded
+ if(state == PS_LOADED)
+ {
+ // notify plugin about shutdown
+ command_result cr = plugin_shutdown(&Core::getInstance());
+ // wait for all calls to finish
+ access->wait();
+ // cleanup...
+ parent->unregisterCommands(this);
+ if(cr == CR_OK)
+ {
+ ClosePlugin(plugin_lib);
+ state = PS_UNLOADED;
+ access->unlock();
+ return false;
+ }
+ else
{
- dfout << commands[i].name << " : " << commands[i].description << std::endl;
+ con.printerr("Plugin %s has failed to shutdown!\n",name.c_str());
+ state = PS_BROKEN;
+ access->unlock();
+ return false;
}
- */
}
- else
+ else if(state == PS_UNLOADED)
{
- // horrible!
+ access->unlock();
+ return true;
}
+ access->unlock();
+ return false;
}
-Plugin::~Plugin()
+bool Plugin::reload()
+{
+ if(state != PS_LOADED)
+ return false;
+ if(!unload())
+ return false;
+ if(!load())
+ return false;
+ return true;
+}
+
+command_result Plugin::invoke( std::string & command, std::vector <std::string> & parameters)
{
- if(loaded)
+ Core & c = Core::getInstance();
+ command_result cr = CR_NOT_IMPLEMENTED;
+ access->lock_add();
+ if(state == PS_LOADED)
{
- plugin_shutdown(&Core::getInstance());
- ClosePlugin(plugin_lib);
+ for (int i = 0; i < commands.size();i++)
+ {
+ if(commands[i].name == command)
+ {
+ cr = commands[i].function(&c, parameters);
+ break;
+ }
+ }
}
+ access->lock_sub();
+ return cr;
}
-bool Plugin::isLoaded() const
+command_result Plugin::on_update()
{
- return loaded;
+ Core & c = Core::getInstance();
+ command_result cr = CR_NOT_IMPLEMENTED;
+ access->lock_add();
+ if(state == PS_LOADED && plugin_onupdate)
+ {
+ cr = plugin_onupdate(&c);
+ }
+ access->lock_sub();
+ return cr;
+}
+
+Plugin::plugin_state Plugin::getState() const
+{
+ return state;
}
PluginManager::PluginManager(Core * core)
@@ -143,18 +313,14 @@ PluginManager::PluginManager(Core * core)
string path = core->p->getPath() + "\\plugins\\";
const string searchstr = ".plug.dll";
#endif
+ cmdlist_mutex = SDL_CreateMutex();
vector <string> filez;
getdir(path, filez);
for(int i = 0; i < filez.size();i++)
{
if(hasEnding(filez[i],searchstr))
{
- Plugin * p = new Plugin(core, path + filez[i]);
- Plugin & pr = *p;
- for(int j = 0; j < pr.size();j++)
- {
- commands[p->commands[j].name] = &pr[j];
- }
+ Plugin * p = new Plugin(core, path + filez[i], filez[i], this);
all_plugins.push_back(p);
}
}
@@ -162,15 +328,15 @@ PluginManager::PluginManager(Core * core)
PluginManager::~PluginManager()
{
- commands.clear();
for(int i = 0; i < all_plugins.size();i++)
{
delete all_plugins[i];
}
all_plugins.clear();
+ SDL_DestroyMutex(cmdlist_mutex);
}
-const Plugin *PluginManager::getPluginByName (const std::string & name)
+Plugin *PluginManager::getPluginByName (const std::string & name)
{
for(int i = 0; i < all_plugins.size(); i++)
{
@@ -183,23 +349,45 @@ const Plugin *PluginManager::getPluginByName (const std::string & name)
// FIXME: handle name collisions...
command_result PluginManager::InvokeCommand( std::string & command, std::vector <std::string> & parameters)
{
+ command_result cr = CR_NOT_IMPLEMENTED;
Core * c = &Core::getInstance();
- map <string, const PluginCommand *>::iterator iter = commands.find(command);
- if(iter != commands.end())
+ SDL_mutexP(cmdlist_mutex);
+ map <string, Plugin *>::iterator iter = belongs.find(command);
+ if(iter != belongs.end())
{
- return iter->second->function(c,parameters);
+ cr = iter->second->invoke(command, parameters);
}
- return CR_NOT_IMPLEMENTED;
+ SDL_mutexV(cmdlist_mutex);
+ return cr;
}
void PluginManager::OnUpdate( void )
{
- Core * c = &Core::getInstance();
for(int i = 0; i < all_plugins.size(); i++)
{
- if(all_plugins[i]->plugin_onupdate)
- {
- all_plugins[i]->plugin_onupdate(c);
- }
+ all_plugins[i]->on_update();
+ }
+}
+// FIXME: doesn't check name collisions!
+void PluginManager::registerCommands( Plugin * p )
+{
+ SDL_mutexP(cmdlist_mutex);
+ vector <PluginCommand> & cmds = p->commands;
+ for(int i = 0; i < cmds.size();i++)
+ {
+ belongs[cmds[i].name] = p;
}
+ SDL_mutexV(cmdlist_mutex);
}
+
+// FIXME: doesn't check name collisions!
+void PluginManager::unregisterCommands( Plugin * p )
+{
+ SDL_mutexP(cmdlist_mutex);
+ vector <PluginCommand> & cmds = p->commands;
+ for(int i = 0; i < cmds.size();i++)
+ {
+ belongs.erase(cmds[i].name);
+ }
+ SDL_mutexV(cmdlist_mutex);
+} \ No newline at end of file