RTXI  2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
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 {
29 }
30 
32 {
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  std::string plugin_dir = std::string(EXEC_PREFIX) + std::string("/lib/rtxi/");
54  handle = dlopen((plugin_dir+library.toStdString()).c_str(),RTLD_GLOBAL|RTLD_NOW);
55  }
56  if (!handle)
57  {
58  ERROR_MSG("Plugin::load : failed to load %s: %s\n",library.toStdString().c_str(),dlerror());
59  return 0;
60  }
61 
62  /*********************************************************************************
63  * Apparently ISO C++ forbids against casting object pointer -> function pointer *
64  * But what the hell do they know? It is probably safe here... *
65  *********************************************************************************/
66 
67  Object *(*create)(void) = (Object *(*)(void))(dlsym(handle,"createRTXIPlugin"));
68  if (!create)
69  {
70  ERROR_MSG("Plugin::load : failed to load %s : %s\n",library.toStdString().c_str(),dlerror());
71  dlclose(handle);
72  return 0;
73  }
74 
75  Object *plugin = create();
76  if (!plugin)
77  {
78  ERROR_MSG("Plugin::load : failed to load %s : failed to create instance\n",library.toStdString().c_str());
79  dlclose(handle);
80  return 0;
81  }
83  {
84  ERROR_MSG("Plugin::load : the pointer returned from %s::createRTXIPlugin() isn't a valid Plugin::Object *.\n",library.toStdString().c_str());
85  dlclose(handle);
86  return 0;
87  }
88 
89  plugin->handle = handle;
90  plugin->library = library.toStdString();
91 
93  event.setParam("plugin",plugin);
94  Event::Manager::getInstance()->postEvent(&event);
95 
96  return plugin;
97 }
98 
100 {
101  if (!plugin)
102  {
103  ERROR_MSG("Plugin::Manager::unload : invalid plugin\n");
104  return;
105  }
106 
107  /* Unfortunate but we have to recast to properly
108  * insert this event into the queue for QT and RTXI
109  * to process.
110  */
111  RTXIEvent *event = new RTXIEvent();
112  event->data = reinterpret_cast<void *>(plugin);
113  QApplication::postEvent(this,reinterpret_cast<QEvent *>(event));
114 }
115 
117 {
118  void *handle;
119  for (std::list<Object *>::iterator i = pluginList.begin(); i != pluginList.end(); i = pluginList.begin())
120  {
122  event.setParam("plugin",*i);
123  Event::Manager::getInstance()->postEvent(&event);
124 
125  handle = (*i)->handle;
126  delete *i;
127  dlclose(handle);
128  }
129 }
130 
131 void Plugin::Manager::foreachPlugin(void (*callback)(Plugin::Object *,void *),void *param)
132 {
133  Mutex::Locker lock(&mutex);
134  for (std::list<Plugin::Object *>::iterator i = pluginList.begin(); i != pluginList.end(); ++i)
135  callback(*i,param);
136 }
137 
139 {
140  if (!plugin)
141  {
142  ERROR_MSG("Plugin::Manager::insertPlugin : invalid plugin\n");
143  return;
144  }
145 
146  Mutex::Locker lock(&mutex);
147  pluginList.push_back(plugin);
148 }
149 
151 {
152  if (!plugin)
153  {
154  ERROR_MSG("Plugin::Manager::removePlugin : invalid plugin\n");
155  return;
156  }
157 
158  Mutex::Locker lock(&mutex);
159  pluginList.remove(plugin);
160 }
161 
163 {
164  if (e->type() == CloseEvent)
165  {
166  RTXIEvent *e2 = reinterpret_cast<RTXIEvent *>(e);
167 
168  Mutex::Locker lock(&mutex);
169 
170  Object *plugin = reinterpret_cast<Plugin::Object *>(e2->data);
171 
173  event.setParam("plugin",plugin);
174  Event::Manager::getInstance()->postEvent(&event);
175 
176  void *handle = plugin->handle;
177  delete plugin;
178  if(handle)
179  dlclose(handle);
180  }
181 }
182 
183 static Mutex mutex;
185 
187 {
188  if (instance)
189  return instance;
190 
191  /*************************************************************************
192  * Seems like alot of hoops to jump through, but static allocation isn't *
193  * thread-safe. So effort must be taken to ensure mutual exclusion. *
194  *************************************************************************/
195 
196  Mutex::Locker lock(&::mutex);
197  if (!instance)
198  {
199  static Manager manager;
200  instance = &manager;
201  }
202 
203  return instance;
204 }
Object(void)
Definition: plugin.cpp:26
static const u_int32_t MAGIC_NUMBER
Definition: plugin.h:170
void removePlugin(Object *)
Definition: plugin.cpp:150
void * data
Definition: plugin.h:51
Definition: mutex.h:28
#define ERROR_MSG(fmt, args...)
Definition: debug.h:41
static Manager * getInstance(void)
Definition: event.cpp:149
const char * PLUGIN_INSERT_EVENT
Definition: event.cpp:36
static Manager * instance
Definition: plugin.h:128
void unload(void)
Definition: plugin.cpp:41
void unload(Object *object)
Definition: plugin.cpp:99
const char * PLUGIN_REMOVE_EVENT
Definition: event.cpp:37
Object * load(const QString &library)
Definition: plugin.cpp:46
void unloadAll(void)
Definition: plugin.cpp:116
static Manager * getInstance(void)
Definition: plugin.cpp:186
void foreachPlugin(void(*callback)(Plugin::Object *, void *), void *param)
Definition: plugin.cpp:131
std::string library
Definition: plugin.h:172
virtual ~Object(void)
Definition: plugin.cpp:31
void * handle
Definition: plugin.h:173
void customEvent(QEvent *)
Definition: plugin.cpp:162
Classes associated with the loading/unloading of binaries at run-time.
Definition: plugin.h:35
std::string getLibrary(void) const
Definition: plugin.cpp:36
u_int32_t magic_number
Definition: plugin.h:171
void insertPlugin(Object *)
Definition: plugin.cpp:138