OpenASIP 2.2
Loading...
Searching...
No Matches
PluginTools.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2009 Tampere University.
3
4 This file is part of TTA-Based Codesign Environment (TCE).
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23 */
24/**
25 * @file PluginTools.cc
26 *
27 * Definition of PluginTools class.
28 *
29 * @author Jussi Nykänen 2004 (nykanen-no.spam-cs.tut.fi)
30 * @author Pekka Jääskeläinen 2005 (pjaaskel-no.spam-cs.tut.fi)
31 * @note reviewed 19 May 2004 by ml, jn, ao, am
32 * @note rating: green
33 */
34
35#include <string>
36#include <vector>
37#include <dlfcn.h>
38
39// this is not defined with all compilers
40#ifndef RTLD_LOCAL
41#define RTLD_LOCAL 0
42#endif
43
44#include <iostream>
45
46#include "PluginTools.hh"
47#include "FileSystem.hh"
48#include "MapTools.hh"
49#include "Exception.hh"
50#include "ContainerTools.hh"
51#include "StringTools.hh"
52
53using std::string;
54using std::vector;
55using std::cout;
56using std::endl;
57
58
59/**
60 * Constructor.
61 *
62 * The created instance has no search paths registered.
63 *
64 * @param lazyResolution True if symbol resolution should be done
65 * lazily.
66 * @param localResolution True in case the symbols are loaded locally
67 * to the process only and not made visible to later plugin loads.
68 *
69 * @note Throwing C++ exceptions from plugin to the loader might not work
70 * with the lazy resolution! It's probably safest to set the argument to
71 * "false".
72 */
73PluginTools::PluginTools(bool lazyResolution, bool local) :
74 lazyResolution_(lazyResolution), localResolution_(local) {
75}
76
77
78/**
79 * Destructor.
80 *
81 * Unregisters all modules.
82 */
86
87
88/**
89 * Adds a new search path in search path list.
90 *
91 * @param searchPath The search path to be added.
92 * @exception FileNotFound If path doesn't exist.
93 */
94void
95PluginTools::addSearchPath(const std::string& searchPath) {
96 if (!(FileSystem::fileExists(searchPath))) {
97 string method = "PluginTools::addSearchPath()";
98 string message = "Path doesn't exist";
99 throw FileNotFound(__FILE__, __LINE__, method, message);
100 }
101 searchPaths_.push_back(searchPath);
102}
103
104/**
105 * Removes search path from search path list if it is found.
106 *
107 * @param searchPath the search path to be removed.
108 */
109void
110PluginTools::removeSearchPath(const std::string& searchPath) {
112}
113
114
115/**
116 * Clears all search paths from search path list.
117 */
118void
122
123
124/**
125 * Registers a module in registry.
126 *
127 * If module is not an absolute path, then it is searched from search
128 * paths added with addSearchPath() in the order of addition. First
129 * module found is used. If module already exists in the registry,
130 * it's not opened again. RTLD_LOCAL and RTLD_NOW flags are used by
131 * default when opening the module.
132 *
133 * @param module The module to be registered.
134 * @exception FileNotFound If module is not found.
135 * @exception DynamicLibraryException if dlopen() fails.
136 */
137void
138PluginTools::registerModule(const std::string& module) {
139 if (module.empty()) {
140 string method = "PluginTools::registerModule()";
141 string message = "Empty module file name.";
142 throw FileNotFound(__FILE__, __LINE__, method, message);
143 }
144
146
147 string path = module;
148 if (!FileSystem::isAbsolutePath(module)) {
149
150 bool moduleFound = false;
151
152 // module is not an absolute path
153 for (unsigned int i = 0; i < searchPaths_.size(); i++) {
154 path = searchPaths_[i] + DIR_SEP + module;
155 if (FileSystem::fileExists(path)) {
156 moduleFound = true;
157 break;
158 }
159 }
160
161 if (!moduleFound) {
162 string method = "PluginTools::registerModule()";
163 string message = "Module not found";
164 throw FileNotFound(__FILE__, __LINE__, method, message);
165 }
166 }
167
168 // multiple registrations are ignored
169 if (!MapTools::containsKey(modules_, path)) {
170
171 void* handle = NULL;
172
173 int flags = 0;
174 if (lazyResolution_) {
175 flags |= RTLD_LAZY;
176 } else {
177 flags |= RTLD_NOW;
178 }
179
180 if (localResolution_) {
181 flags |= RTLD_LOCAL;
182 } else {
183 flags |= RTLD_GLOBAL;
184 }
185
186 handle = dlopen(path.c_str(), flags);
187
188 if (handle == NULL) {
189 string method = "PluginTools::registerModule()";
190 string message = dlerror();
191 throw DynamicLibraryException(__FILE__, __LINE__, method, message);
192 }
193
194 modules_.insert(ValType(path, handle));
195 }
196}
197
198/**
199 * A module is closed using dlclose() and it is removed from registry.
200 *
201 * @param module The module to be unregistered.
202 * @exception FileNotFound If module is not found.
203 * @exception DynamicLibraryException If dlclose() fails.
204 * @exception MultipleInstancesFound If multiple modules are found.
205 */
206void
207PluginTools::unregisterModule(const std::string& module) {
208 string method = "PluginTools::unregisterModule()";
209 string path = module;
210 if (!FileSystem::isAbsolutePath(module)) {
211 path = findModule(module);
212 }
213
214 MapIter mt = modules_.find(path);
215 if (mt == modules_.end()) {
216 string msg = "Module not found";
217 throw FileNotFound(__FILE__, __LINE__, method, msg);
218 }
219
220 void* handle = (*mt).second;
221 modules_.erase(mt);
222 if (dlclose(handle) != 0) {
223 string message = dlerror();
224 throw DynamicLibraryException(__FILE__, __LINE__, method, message);
225 }
226}
227
228/**
229 * Unregisters all modules.
230 *
231 * All modules are closed by using dlclose() and registry is emptied.
232 *
233 * @exception DynamicLibraryException If dlclose() fails.
234 */
235void
237 MapIter mt;
238 for (mt = modules_.begin(); mt != modules_.end(); mt++) {
239 void* handle = (*mt).second;
240 std::string moduleName = (*mt).first;
241 dlclose(handle);
242 // Removing check. This is called on the global destructor
243 // stage and in some systems (FreeBSD) libraries are already
244 // unloaded by then which would cause this to fail unneccessarily.
245// if (dlclose(handle) != 0) {
246// string method = "PluginTools::unregisterAllModules()";
247// string message = dlerror();
248// throw DynamicLibraryException(__FILE__, __LINE__, method, message);
249// }
250 }
251 modules_.clear();
252}
253
254/**
255 * Loads symbol from module.
256 *
257 * If module is not given, then all modules are searched in order to
258 * find the symbol. Note that the search order of modules is not necessarily
259 * the same as the registration order!
260 *
261 * @param symbolName The symbol being loaded.
262 * @param module The module where symbol is loaded.
263 * @return Pointer to loaded symbol.
264 * @exception MultipleInstancesFound If multiple instances of module are
265 * found.
266 * @exception DynamicLibraryException If dlsym() fails.
267 * @exception FileNotFound If module is not found.
268 * @exception SymbolNotFound If symbol to be loaded is not found.
269 */
270void*
271PluginTools::loadSym(const std::string& symbolName, const std::string& module) {
272 string path = module;
273 if (module != "") {
274
275 if (!FileSystem::isAbsolutePath(module)) {
276 try {
277 path = findModule(module);
278 } catch (const FileNotFound& f) {
279 // file was not found, so let's try to register it.
280 registerModule(module);
281 path = findModule(module);
282 }
283 } else {
284 if (!MapTools::containsKey(modules_, path)) {
285 registerModule(path);
286 }
287 }
288
289 MapIter mt = modules_.find(path);
290 void* handle = (*mt).second;
291 const char* error = NULL;
292
293 // clear possible old errors
294 dlerror();
295
296 void* sym = dlsym(handle, symbolName.c_str());
297 if ((error = dlerror()) != NULL) {
298 if (sym == NULL) {
299 // it does not seem to be possible to separate the
300 // symbol not found error from other errors, thus this will
301 // probably always throw SymbolNotFound in case the symbol
302 // could not be loaded for any reason
303 string message = "Symbol not found: ";
304 message += symbolName;
305 throw SymbolNotFound(__FILE__, __LINE__, __func__, message);
306 } else {
308 __FILE__, __LINE__, __func__, error);
309 }
310 }
311
312 return sym;
313
314 } else {
315
316 // seek all registered modules for the symbol and return the first
317 // one found
318 for (MapIter mt = modules_.begin(); mt != modules_.end(); mt++) {
319 void* handle = (*mt).second;
320 const char* error = NULL;
321 dlerror();
322 void* sym = dlsym(handle, symbolName.c_str());
323 if ((error = dlerror()) == NULL) {
324 return sym;
325 }
326 }
327
328 // symbol was not found, exception is thrown
329 string method = "PluginTools::loadSym()";
330 string message = "Symbol not found";
331 throw SymbolNotFound(__FILE__, __LINE__, method, message);
332 }
333
334 return NULL;
335}
336
337/**
338 * Looks for the path for the module and returns it if it is found.
339 *
340 * @param module The module to be searched for.
341 * @return The path for the module.
342 * @exception MultipleInstacesFound If multiple instances of module are found.
343 * @exception FileNotFOund If module is not found at all.
344 */
345string
346PluginTools::findModule(const std::string& module) {
347 string path = "";
348 bool moduleFound = false;
349 for (MapIter mt = modules_.begin(); mt != modules_.end(); mt++) {
350
351 const string fullPath = (*mt).first;
352 const string fileName = FileSystem::fileOfPath(fullPath);
353 if (module == fullPath ||
354 module == fileName ||
355 StringTools::endsWith(fullPath, std::string("/") + module)) {
356
357 if (moduleFound) {
358 string method = "PluginTools::findModule()";
359 string message = "Multiple modules found";
361 __FILE__, __LINE__, method, message);
362 }
363
364 path = (*mt).first;
365 moduleFound = true;
366 }
367 }
368
369 if (!moduleFound) {
370 string method = "PluginTools::findModule()";
371 string message = "Module not found";
372 throw FileNotFound(__FILE__, __LINE__, method, message);
373 }
374
375 return path;
376}
#define __func__
const string DIR_SEP
#define RTLD_LOCAL
static bool removeValueIfExists(ContainerType &aContainer, const ElementType &aKey)
static bool isAbsolutePath(const std::string &pathName)
static const std::string DIRECTORY_SEPARATOR
static std::string fileOfPath(const std::string pathName)
static bool fileExists(const std::string fileName)
static bool containsKey(const MapType &aMap, const KeyType &aKey)
bool localResolution_
True if the symbols defined in the loaded library should be made available for symbol resolution of s...
void addSearchPath(const std::string &searchPath)
void clearSearchPaths()
std::vector< std::string > searchPaths_
Search paths of dynamic modules.
PluginTools(bool lazyResolution=true, bool local=false)
bool lazyResolution_
True if all undefined symbols should be resolved only when needed.
void unregisterAllModules()
virtual ~PluginTools()
std::map< std::string, void * > modules_
Map containing opened module handles.
void unregisterModule(const std::string &module)
std::string findModule(const std::string &module)
std::map< std::string, void * >::iterator MapIter
void removeSearchPath(const std::string &searchPath)
std::map< std::string, void * >::value_type ValType
void * loadSym(const std::string &symbolName, const std::string &module="")
void registerModule(const std::string &module)
static bool endsWith(const std::string &source, const std::string &searchString)