![]() |
RTXI 1.3
|
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 }