RTXI 1.3
src/plugin.cpp
Go to the documentation of this file.
00001 /*
00002  Copyright (C) 2011 Georgia Institute of Technology, University of Utah, Weill Cornell Medical College
00003 
00004  This program is free software: you can redistribute it and/or modify
00005  it under the terms of the GNU General Public License as published by
00006  the Free Software Foundation, either version 3 of the License, or
00007  (at your option) any later version.
00008 
00009  This program is distributed in the hope that it will be useful,
00010  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  GNU General Public License for more details.
00013 
00014  You should have received a copy of the GNU General Public License
00015  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017  */
00018 
00019 #include <debug.h>
00020 #include <dlfcn.h>
00021 #include <event.h>
00022 #include <plugin.h>
00023 #include <qapplication.h>
00024 
00025 Plugin::Object::Object(void)
00026     : magic_number(Plugin::Object::MAGIC_NUMBER), handle(0) {
00027     Plugin::Manager::getInstance()->insertPlugin(this);
00028 }
00029 
00030 Plugin::Object::~Object(void) {
00031     Plugin::Manager::getInstance()->removePlugin(this);
00032 }
00033 
00034 std::string Plugin::Object::getLibrary(void) const {
00035     return library;
00036 }
00037 
00038 void Plugin::Object::unload(void) {
00039     Plugin::Manager::getInstance()->unload(this);
00040 }
00041 
00042 Plugin::Object *Plugin::Manager::load(const std::string &library) {
00043     Mutex::Locker lock(&mutex);
00044 
00045     void *handle = dlopen(library.c_str(),RTLD_GLOBAL|RTLD_NOW);
00046     if(!handle) {
00047         std::string plugin_dir = std::string(EXEC_PREFIX) + std::string("/lib/rtxi/");
00048         handle = dlopen((plugin_dir+library).c_str(),RTLD_GLOBAL|RTLD_NOW);
00049     }
00050     if(!handle) {
00051         ERROR_MSG("Plugin::load : failed to load %s: %s\n",library.c_str(),dlerror());
00052         return 0;
00053     }
00054 
00055     /*********************************************************************************
00056      * Apparently ISO C++ forbids against casting object pointer -> function pointer *
00057      *   But what the hell do they know? It is probably safe here...                 *
00058      *********************************************************************************/
00059 
00060     Object *(*create)(void) = (Object *(*)(void))(dlsym(handle,"createRTXIPlugin"));
00061     if(!create) {
00062         ERROR_MSG("Plugin::load : failed to load %s : %s\n",library.c_str(),dlerror());
00063         dlclose(handle);
00064         return 0;
00065     }
00066 
00067     Object *plugin = create();
00068     if(!plugin) {
00069         ERROR_MSG("Plugin::load : failed to load %s : failed to create instance\n",library.c_str());
00070         dlclose(handle);
00071         return 0;
00072     }
00073     if(plugin->magic_number != Plugin::Object::MAGIC_NUMBER) {
00074         ERROR_MSG("Plugin::load : the pointer returned from %s::createRTXIPlugin() isn't a valid Plugin::Object *.\n",library.c_str());
00075         dlclose(handle);
00076         return 0;
00077     }
00078 
00079     plugin->handle = handle;
00080     plugin->library = library;
00081 
00082     Event::Object event(Event::PLUGIN_INSERT_EVENT);
00083     event.setParam("plugin",plugin);
00084     Event::Manager::getInstance()->postEvent(&event);
00085 
00086     return plugin;
00087 }
00088 
00089 void Plugin::Manager::unload(Plugin::Object *plugin) {
00090     if(!plugin) {
00091         ERROR_MSG("Plugin::Manager::unload : invalid plugin\n");
00092         return;
00093     }
00094 
00095     QCustomEvent *event = new QCustomEvent(CloseEvent,reinterpret_cast<void *>(plugin));
00096     QApplication::postEvent(this,event);
00097 }
00098 
00099 void Plugin::Manager::unloadAll(void) {
00100     void *handle;
00101     for(std::list<Object *>::iterator i = pluginList.begin();i != pluginList.end();i = pluginList.begin()) {
00102         Event::Object event(Event::PLUGIN_REMOVE_EVENT);
00103         event.setParam("plugin",*i);
00104         Event::Manager::getInstance()->postEvent(&event);
00105 
00106         handle = (*i)->handle;
00107         delete *i;
00108         dlclose(handle);
00109     }
00110 }
00111 
00112 void Plugin::Manager::foreachPlugin(void (*callback)(Plugin::Object *,void *),void *param) {
00113     Mutex::Locker lock(&mutex);
00114     for(std::list<Plugin::Object *>::iterator i = pluginList.begin();i != pluginList.end();++i)
00115         callback(*i,param);
00116 }
00117 
00118 void Plugin::Manager::insertPlugin(Plugin::Object *plugin) {
00119     if(!plugin) {
00120         ERROR_MSG("Plugin::Manager::insertPlugin : invalid plugin\n");
00121         return;
00122     }
00123 
00124     Mutex::Locker lock(&mutex);
00125     pluginList.push_back(plugin);
00126 }
00127 
00128 void Plugin::Manager::removePlugin(Plugin::Object *plugin) {
00129     if(!plugin) {
00130         ERROR_MSG("Plugin::Manager::removePlugin : invalid plugin\n");
00131         return;
00132     }
00133 
00134     Mutex::Locker lock(&mutex);
00135     pluginList.remove(plugin);
00136 }
00137 
00138 void Plugin::Manager::customEvent(QCustomEvent *e) {
00139     if(e->type() == CloseEvent) {
00140         Mutex::Locker lock(&mutex);
00141 
00142         Object *plugin = static_cast<Plugin::Object *>(e->data());
00143 
00144         Event::Object event(Event::PLUGIN_REMOVE_EVENT);
00145         event.setParam("plugin",plugin);
00146         Event::Manager::getInstance()->postEvent(&event);
00147 
00148         void *handle = plugin->handle;
00149         delete plugin;
00150         if(handle) dlclose(handle);
00151     }
00152 }
00153 
00154 static Mutex mutex;
00155 Plugin::Manager *Plugin::Manager::instance = 0;
00156 
00157 Plugin::Manager *Plugin::Manager::getInstance(void) {
00158     if(instance)
00159         return instance;
00160 
00161     /*************************************************************************
00162      * Seems like alot of hoops to jump through, but static allocation isn't *
00163      *   thread-safe. So effort must be taken to ensure mutual exclusion.    *
00164      *************************************************************************/
00165 
00166     Mutex::Locker lock(&::mutex);
00167     if(!instance) {
00168         static Manager manager;
00169         instance = &manager;
00170     }
00171 
00172     return instance;
00173 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines