OpenASIP  2.0
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 
53 using std::string;
54 using std::vector;
55 using std::cout;
56 using 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  */
73 PluginTools::PluginTools(bool lazyResolution, bool local) :
74  lazyResolution_(lazyResolution), localResolution_(local) {
75 }
76 
77 
78 /**
79  * Destructor.
80  *
81  * Unregisters all modules.
82  */
85 }
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  */
94 void
95 PluginTools::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  */
109 void
110 PluginTools::removeSearchPath(const std::string& searchPath) {
112 }
113 
114 
115 /**
116  * Clears all search paths from search path list.
117  */
118 void
120  searchPaths_.clear();
121 }
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  */
137 void
138 PluginTools::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  */
206 void
207 PluginTools::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  */
235 void
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  */
270 void*
271 PluginTools::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  */
345 string
346 PluginTools::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 }
StringTools::endsWith
static bool endsWith(const std::string &source, const std::string &searchString)
Definition: StringTools.cc:126
FileSystem.hh
FileNotFound
Definition: Exception.hh:224
PluginTools::ValType
std::map< std::string, void * >::value_type ValType
Definition: PluginTools.hh:76
PluginTools::findModule
std::string findModule(const std::string &module)
Definition: PluginTools.cc:346
Exception.hh
MultipleInstancesFound
Definition: Exception.hh:605
MapTools.hh
PluginTools::searchPaths_
std::vector< std::string > searchPaths_
Search paths of dynamic modules.
Definition: PluginTools.hh:89
FileSystem::fileOfPath
static std::string fileOfPath(const std::string pathName)
Definition: FileSystem.cc:101
PluginTools::removeSearchPath
void removeSearchPath(const std::string &searchPath)
Definition: PluginTools.cc:110
PluginTools::localResolution_
bool localResolution_
True if the symbols defined in the loaded library should be made available for symbol resolution of s...
Definition: PluginTools.hh:97
StringTools.hh
PluginTools::PluginTools
PluginTools(bool lazyResolution=true, bool local=false)
Definition: PluginTools.cc:73
PluginTools::loadSym
void * loadSym(const std::string &symbolName, const std::string &module="")
Definition: PluginTools.cc:271
PluginTools::unregisterModule
void unregisterModule(const std::string &module)
Definition: PluginTools.cc:207
PluginTools::~PluginTools
virtual ~PluginTools()
Definition: PluginTools.cc:83
SymbolNotFound
Definition: Exception.hh:623
ContainerTools::removeValueIfExists
static bool removeValueIfExists(ContainerType &aContainer, const ElementType &aKey)
__func__
#define __func__
Definition: Application.hh:67
PluginTools::registerModule
void registerModule(const std::string &module)
Definition: PluginTools.cc:138
PluginTools.hh
FileSystem::DIRECTORY_SEPARATOR
static const std::string DIRECTORY_SEPARATOR
Definition: FileSystem.hh:189
DIR_SEP
const string DIR_SEP
Definition: GenerateBits.cc:71
MapTools::containsKey
static bool containsKey(const MapType &aMap, const KeyType &aKey)
PluginTools::modules_
std::map< std::string, void * > modules_
Map containing opened module handles.
Definition: PluginTools.hh:91
PluginTools::addSearchPath
void addSearchPath(const std::string &searchPath)
Definition: PluginTools.cc:95
FileSystem::fileExists
static bool fileExists(const std::string fileName)
PluginTools::clearSearchPaths
void clearSearchPaths()
Definition: PluginTools.cc:119
DynamicLibraryException
Definition: Exception.hh:588
FileSystem::isAbsolutePath
static bool isAbsolutePath(const std::string &pathName)
Definition: FileSystem.cc:234
PluginTools::MapIter
std::map< std::string, void * >::iterator MapIter
Definition: PluginTools.hh:75
RTLD_LOCAL
#define RTLD_LOCAL
Definition: PluginTools.cc:41
PluginTools::lazyResolution_
bool lazyResolution_
True if all undefined symbols should be resolved only when needed.
Definition: PluginTools.hh:94
PluginTools::unregisterAllModules
void unregisterAllModules()
Definition: PluginTools.cc:236
ContainerTools.hh