RTXI  2.4
The Real-Time eXperiment Interface Documentation
plugin.cpp
Go to the documentation of this file.
1 /*
2  The Real-Time eXperiment Interface (RTXI)
3  Copyright (C) 2011 Georgia Institute of Technology, University of Utah, Weill Cornell Medical College
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 
20 #include <QApplication>
21 #include <debug.h>
22 #include <dlfcn.h>
23 #include <event.h>
24 #include <plugin.h>
25 
26 Plugin::Object::Object(void) : magic_number(Plugin::Object::MAGIC_NUMBER), handle(0)
27 {
28  Plugin::Manager::getInstance()->insertPlugin(this);
29 }
30 
32 {
33  Plugin::Manager::getInstance()->removePlugin(this);
34 }
35 
36 std::string Plugin::Object::getLibrary(void) const
37 {
38  return library;
39 }
40 
42 {
44 }
45 
46 Plugin::Object *Plugin::Manager::load(const QString &library)
47 {
48  Mutex::Locker lock(&mutex);
49 
50  void *handle = dlopen(library.toStdString().c_str(),RTLD_GLOBAL|RTLD_NOW);
51  if (!handle)
52  {
53  //ERROR_MSG("Plugin::load : failed to load library: %s", dlerror());
54  std::string plugin_dir = std::string(EXEC_PREFIX) + std::string("/lib/rtxi/");
55  handle = dlopen((plugin_dir+library.toStdString()).c_str(),RTLD_GLOBAL|RTLD_NOW);
56  }
57  if (!handle)
58  {
59  ERROR_MSG("Plugin::load : failed to load %s: %s\n",library.toStdString().c_str(),dlerror());
60  return 0;
61  }
62 
63  /*********************************************************************************
64  * Apparently ISO C++ forbids against casting object pointer -> function pointer *
65  * But what the hell do they know? It is probably safe here... *
66  *********************************************************************************/
67 
68  Object *(*create)(void) = (Object *(*)(void))(dlsym(handle,"createRTXIPlugin"));
69  if (!create)
70  {
71  ERROR_MSG("Plugin::load : failed to load %s : %s\n",library.toStdString().c_str(),dlerror());
72  dlclose(handle);
73  return 0;
74  }
75 
76  Object *plugin = create();
77  if (!plugin)
78  {
79  ERROR_MSG("Plugin::load : failed to load %s : failed to create instance\n",library.toStdString().c_str());
80  dlclose(handle);
81  return 0;
82  }
83  if (plugin->magic_number != Plugin::Object::MAGIC_NUMBER)
84  {
85  ERROR_MSG("Plugin::load : the pointer returned from %s::createRTXIPlugin() isn't a valid Plugin::Object *.\n",library.toStdString().c_str());
86  dlclose(handle);
87  return 0;
88  }
89 
90  plugin->handle = handle;
91  plugin->library = library.toStdString();
92 
94  event.setParam("plugin",plugin);
95  Event::Manager::getInstance()->postEvent(&event);
96 
97  return plugin;
98 }
99 
101 {
102  if (!plugin)
103  {
104  ERROR_MSG("Plugin::Manager::unload : invalid plugin\n");
105  return;
106  }
107 
108  /* Unfortunate but we have to recast to properly
109  * insert this event into the queue for QT and RTXI
110  * to process.
111  */
112  RTXIEvent *event = new RTXIEvent();
113  event->data = reinterpret_cast<void *>(plugin);
114  QApplication::postEvent(this,reinterpret_cast<QEvent *>(event));
115 }
116 
118 {
119  void *handle;
120  for (std::list<Object *>::iterator i = pluginList.begin(); i != pluginList.end(); i = pluginList.begin())
121  {
123  event.setParam("plugin",*i);
124  Event::Manager::getInstance()->postEvent(&event);
125 
126  handle = (*i)->handle;
127  delete *i;
128  dlclose(handle);
129  }
130 }
131 
132 void Plugin::Manager::foreachPlugin(void (*callback)(Plugin::Object *,void *),void *param)
133 {
134  Mutex::Locker lock(&mutex);
135  for (std::list<Plugin::Object *>::iterator i = pluginList.begin(); i != pluginList.end(); ++i)
136  callback(*i,param);
137 }
138 
139 void Plugin::Manager::insertPlugin(Plugin::Object *plugin)
140 {
141  if (!plugin)
142  {
143  ERROR_MSG("Plugin::Manager::insertPlugin : invalid plugin\n");
144  return;
145  }
146 
147  Mutex::Locker lock(&mutex);
148  pluginList.push_back(plugin);
149 }
150 
151 void Plugin::Manager::removePlugin(Plugin::Object *plugin)
152 {
153  if (!plugin)
154  {
155  ERROR_MSG("Plugin::Manager::removePlugin : invalid plugin\n");
156  return;
157  }
158 
159  Mutex::Locker lock(&mutex);
160  // TODO: uhhh removing a plugin by calling plugin destructor, which calls this function... not good.
161  pluginList.remove(plugin);
162 }
163 
165 {
166  if (e->type() == CloseEvent)
167  {
168  RTXIEvent *e2 = reinterpret_cast<RTXIEvent *>(e);
169 
170  Mutex::Locker lock(&mutex);
171 
172  Object *plugin = reinterpret_cast<Plugin::Object *>(e2->data);
173 
175  event.setParam("plugin",plugin);
176  Event::Manager::getInstance()->postEvent(&event);
177 
178  void *handle = plugin->handle;
179  delete plugin;
180  if(handle)
181  dlclose(handle);
182  }
183 }
184 
185 static Mutex mutex;
186 Plugin::Manager *Plugin::Manager::instance = 0;
187 
189 {
190  if (instance)
191  return instance;
192 
193  /*************************************************************************
194  * Seems like alot of hoops to jump through, but static allocation isn't *
195  * thread-safe. So effort must be taken to ensure mutual exclusion. *
196  *************************************************************************/
197 
198  Mutex::Locker lock(&::mutex);
199  if (!instance)
200  {
201  static Manager manager;
202  instance = &manager;
203  }
204 
205  return instance;
206 }
Plugin::Manager::unload
void unload(Object *object)
Definition: plugin.cpp:100
Plugin::Object::~Object
virtual ~Object(void)
Definition: plugin.cpp:31
Plugin::Manager::load
Object * load(const QString &library)
Definition: plugin.cpp:46
ERROR_MSG
void ERROR_MSG(const std::string &errmsg,...)
Definition: debug.cpp:27
Event::Manager::getInstance
static Manager * getInstance(void)
Definition: event.cpp:149
Plugin::Object
Definition: plugin.h:145
plugin.h
Plugin::RTXIEvent
Definition: plugin.h:46
Plugin::Object::Object
Object(void)
Definition: plugin.cpp:26
Plugin::Manager
Definition: plugin.h:57
Mutex
Definition: mutex.h:28
event.h
Plugin::RTXIEvent::data
void * data
Definition: plugin.h:51
Plugin
Classes associated with the loading/unloading of binaries at run-time.
Definition: plugin.h:35
Plugin::Manager::getInstance
static Manager * getInstance(void)
Definition: plugin.cpp:188
Mutex::Locker
Definition: mutex.h:36
Plugin::Manager::foreachPlugin
void foreachPlugin(void(*callback)(Plugin::Object *, void *), void *param)
Definition: plugin.cpp:132
Plugin::Manager::customEvent
void customEvent(QEvent *)
Definition: plugin.cpp:164
Plugin::Manager::unloadAll
void unloadAll(void)
Definition: plugin.cpp:117
Event::Object
Definition: event.h:128
Plugin::Object::unload
void unload(void)
Definition: plugin.cpp:41
Event::PLUGIN_INSERT_EVENT
const char * PLUGIN_INSERT_EVENT
Definition: event.cpp:36
Event::PLUGIN_REMOVE_EVENT
const char * PLUGIN_REMOVE_EVENT
Definition: event.cpp:37
Plugin::Object::getLibrary
std::string getLibrary(void) const
Definition: plugin.cpp:36
debug.h