class_loader_core.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2012, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  * * Neither the name of the copyright holders nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifndef CLASS_LOADER__CLASS_LOADER_CORE_HPP_
33 #define CLASS_LOADER__CLASS_LOADER_CORE_HPP_
34 
35 #include <boost/thread/recursive_mutex.hpp>
36 #include <cstddef>
37 #include <cstdio>
38 #include <map>
39 #include <string>
40 #include <typeinfo>
41 #include <utility>
42 #include <vector>
43 
47 
48 // forward declaration
49 namespace Poco
50 {
51  class SharedLibrary;
52 } // namespace Poco
53 
58 namespace class_loader
59 {
60 
61 class ClassLoader; // Forward declaration
62 
63 namespace impl
64 {
65 
66 // Typedefs
67 typedef std::string LibraryPath;
68 typedef std::string ClassName;
69 typedef std::string BaseClassName;
70 typedef std::map<ClassName, impl::AbstractMetaObjectBase *> FactoryMap;
71 typedef std::map<BaseClassName, FactoryMap> BaseToFactoryMapMap;
72 typedef std::pair<LibraryPath, Poco::SharedLibrary *> LibraryPair;
73 typedef std::vector<LibraryPair> LibraryVector;
74 typedef std::vector<AbstractMetaObjectBase *> MetaObjectVector;
75 
76 // Debug
79 
80 // Global storage
81 
88 
95 
101 std::string getCurrentlyLoadingLibraryName();
102 
108 void setCurrentlyLoadingLibraryName(const std::string & library_name);
109 
110 
117 
124 
125 
131 FactoryMap & getFactoryMapForBaseClass(const std::string & typeid_base_class_name);
132 
137 template<typename Base>
139 {
140  return getFactoryMapForBaseClass(typeid(Base).name());
141 }
142 
148 boost::recursive_mutex & getLoadedLibraryVectorMutex();
150 boost::recursive_mutex & getPluginBaseToFactoryMapMapMutex();
151 
158 
164 void hasANonPurePluginLibraryBeenOpened(bool hasIt);
165 
166 #if defined(__has_feature)
167 #if __has_feature(address_sanitizer) // for clang
168 #define __SANITIZE_ADDRESS__ // GCC already sets this
169 #endif
170 #endif
171 
172 #if defined(__SANITIZE_ADDRESS__)
173 #include <sanitizer/lsan_interface.h>
174 #endif
175 // Plugin Functions
176 
184 template<typename Derived, typename Base>
185 void registerPlugin(const std::string & class_name, const std::string & base_class_name)
186 {
187  // Note: This function will be automatically invoked when a dlopen() call
188  // opens a library. Normally it will happen within the scope of loadLibrary(),
189  // but that may not be guaranteed.
190  CONSOLE_BRIDGE_logDebug(
191  "class_loader.impl: "
192  "Registering plugin factory for class = %s, ClassLoader* = %p and library name %s.",
193  class_name.c_str(), getCurrentlyActiveClassLoader(),
195 
196  if (nullptr == getCurrentlyActiveClassLoader()) {
197  CONSOLE_BRIDGE_logDebug("%s",
198  "class_loader.impl: ALERT!!! "
199  "A library containing plugins has been opened through a means other than through the "
200  "class_loader or pluginlib package. "
201  "This can happen if you build plugin libraries that contain more than just plugins "
202  "(i.e. normal code your app links against). "
203  "This inherently will trigger a dlopen() prior to main() and cause problems as class_loader "
204  "is not aware of plugin factories that autoregister under the hood. "
205  "The class_loader package can compensate, but you may run into namespace collision problems "
206  "(e.g. if you have the same plugin class in two different libraries and you load them both "
207  "at the same time). "
208  "The biggest problem is that library can now no longer be safely unloaded as the "
209  "ClassLoader does not know when non-plugin code is still in use. "
210  "In fact, no ClassLoader instance in your application will be unable to unload any library "
211  "once a non-pure one has been opened. "
212  "Please refactor your code to isolate plugins into their own libraries.");
214  }
215 
216  // Create factory
217  impl::AbstractMetaObject<Base> * new_factory =
218  new impl::MetaObject<Derived, Base>(class_name, base_class_name);
219 
220 #if defined(__SANITIZE_ADDRESS__)
221  __lsan_ignore_object(new_factory);
222 #endif
223 
226 
227 
228  // Add it to global factory map map
230  FactoryMap & factoryMap = getFactoryMapForBaseClass<Base>();
231  if (factoryMap.find(class_name) != factoryMap.end()) {
232  CONSOLE_BRIDGE_logWarn(
233  "class_loader.impl: SEVERE WARNING!!! "
234  "A namespace collision has occurred with plugin factory for class %s. "
235  "New factory will OVERWRITE existing one. "
236  "This situation occurs when libraries containing plugins are directly linked against an "
237  "executable (the one running right now generating this message). "
238  "Please separate plugins out into their own library or just don't link against the library "
239  "and use either class_loader::ClassLoader/MultiLibraryClassLoader to open.",
240  class_name.c_str());
241  }
242  factoryMap[class_name] = new_factory;
244 
245  CONSOLE_BRIDGE_logDebug(
246  "class_loader.impl: "
247  "Registration of %s complete (Metaobject Address = %p)",
248  class_name.c_str(), reinterpret_cast<void *>(new_factory));
249 }
250 
257 template<typename Base>
258 Base * createInstance(const std::string & derived_class_name, ClassLoader * loader)
259 {
260  AbstractMetaObject<Base> * factory = nullptr;
261 
263  FactoryMap & factoryMap = getFactoryMapForBaseClass<Base>();
264  if (factoryMap.find(derived_class_name) != factoryMap.end()) {
265  factory = dynamic_cast<impl::AbstractMetaObject<Base> *>(factoryMap[derived_class_name]);
266  } else {
267  CONSOLE_BRIDGE_logError(
268  "class_loader.impl: No metaobject exists for class type %s.", derived_class_name.c_str());
269  }
271 
272  Base * obj = nullptr;
273  if (factory != nullptr && factory->isOwnedBy(loader)) {
274  obj = factory->create();
275  }
276 
277  if (nullptr == obj) { // Was never created
278  if (factory && factory->isOwnedBy(nullptr)) {
279  CONSOLE_BRIDGE_logDebug("%s",
280  "class_loader.impl: ALERT!!! "
281  "A metaobject (i.e. factory) exists for desired class, but has no owner. "
282  "This implies that the library containing the class was dlopen()ed by means other than "
283  "through the class_loader interface. "
284  "This can happen if you build plugin libraries that contain more than just plugins "
285  "(i.e. normal code your app links against) -- that intrinsically will trigger a dlopen() "
286  "prior to main(). "
287  "You should isolate your plugins into their own library, otherwise it will not be "
288  "possible to shutdown the library!");
289 
290  obj = factory->create();
291  } else {
293  "Could not create instance of type " + derived_class_name);
294  }
295  }
296 
297  CONSOLE_BRIDGE_logDebug(
298  "class_loader.impl: Created instance of type %s and object pointer = %p",
299  (typeid(obj).name()), reinterpret_cast<void *>(obj));
300 
301  return obj;
302 }
303 
309 template<typename Base>
310 std::vector<std::string> getAvailableClasses(ClassLoader * loader)
311 {
312  boost::recursive_mutex::scoped_lock lock(getPluginBaseToFactoryMapMapMutex());
313 
314  FactoryMap & factory_map = getFactoryMapForBaseClass<Base>();
315  std::vector<std::string> classes;
316  std::vector<std::string> classes_with_no_owner;
317 
318  for (auto & it : factory_map) {
319  AbstractMetaObjectBase * factory = it.second;
320  if (factory->isOwnedBy(loader)) {
321  classes.push_back(it.first);
322  } else if (factory->isOwnedBy(nullptr)) {
323  classes_with_no_owner.push_back(it.first);
324  }
325  }
326 
327  // Added classes not associated with a class loader (Which can happen through
328  // an unexpected dlopen() to the library)
329  classes.insert(classes.end(), classes_with_no_owner.begin(), classes_with_no_owner.end());
330  return classes;
331 }
332 
339 std::vector<std::string> getAllLibrariesUsedByClassLoader(const ClassLoader * loader);
340 
348 bool isLibraryLoaded(const std::string & library_path, ClassLoader * loader);
349 
356 bool isLibraryLoadedByAnybody(const std::string & library_path);
357 
364 void loadLibrary(const std::string & library_path, ClassLoader * loader);
365 
372 void unloadLibrary(const std::string & library_path, ClassLoader * loader);
373 
374 } // namespace impl
375 } // namespace class_loader
376 
377 #endif // CLASS_LOADER__CLASS_LOADER_CORE_HPP_
class_loader::impl::loadLibrary
CLASS_LOADER_PUBLIC void loadLibrary(const std::string &library_path, ClassLoader *loader)
Loads a library into memory if it has not already been done so. Attempting to load an already loaded ...
Definition: class_loader_core.cpp:430
class_loader::impl::LibraryPair
std::pair< LibraryPath, Poco::SharedLibrary * > LibraryPair
Definition: class_loader_core.hpp:72
exceptions.hpp
class_loader::impl::AbstractMetaObject::create
virtual B * create() const =0
Defines the factory interface that the MetaObject must implement.
class_loader::impl::registerPlugin
void registerPlugin(const std::string &class_name, const std::string &base_class_name)
This function is called by the CLASS_LOADER_REGISTER_CLASS macro in plugin_register_macro....
Definition: class_loader_core.hpp:185
class_loader
Definition: class_loader.hpp:50
class_loader::impl::AbstractMetaObjectBase
A base class for MetaObjects that excludes a polymorphic type parameter. Subclasses are class templat...
Definition: meta_object.hpp:59
class_loader::impl::getFactoryMapForBaseClass
CLASS_LOADER_PUBLIC FactoryMap & getFactoryMapForBaseClass(const std::string &typeid_base_class_name)
This function extracts a reference to the FactoryMap for appropriate base class out of the global plu...
Definition: class_loader_core.cpp:68
class_loader::impl::AbstractMetaObjectBase::addOwningClassLoader
void addOwningClassLoader(ClassLoader *loader)
Associates a ClassLoader owner with this factory,.
Definition: meta_object.cpp:86
class_loader::impl::LibraryVector
std::vector< LibraryPair > LibraryVector
Definition: class_loader_core.hpp:73
class_loader::impl::createInstance
Base * createInstance(const std::string &derived_class_name, ClassLoader *loader)
This function creates an instance of a plugin class given the derived name of the class and returns a...
Definition: class_loader_core.hpp:258
class_loader::impl::getCurrentlyLoadingLibraryName
CLASS_LOADER_PUBLIC std::string getCurrentlyLoadingLibraryName()
When a library is being loaded, in order for factories to know which library they are being associate...
Definition: class_loader_core.cpp:97
class_loader::impl::MetaObjectVector
std::vector< AbstractMetaObjectBase * > MetaObjectVector
Definition: class_loader_core.hpp:74
class_loader::impl::AbstractMetaObject
Abstract base class for factories where polymorphic type variable indicates base class for plugin int...
Definition: meta_object.hpp:147
Poco
Definition: class_loader_core.hpp:49
class_loader::impl::getGlobalPluginBaseToFactoryMapMap
CLASS_LOADER_PUBLIC BaseToFactoryMapMap & getGlobalPluginBaseToFactoryMapMap()
Gets a handle to a global data structure that holds a map of base class names (Base class describes p...
Definition: class_loader_core.cpp:62
class_loader::impl::getPluginBaseToFactoryMapMapMutex
CLASS_LOADER_PUBLIC boost::recursive_mutex & getPluginBaseToFactoryMapMapMutex()
Definition: class_loader_core.cpp:56
class_loader::impl::hasANonPurePluginLibraryBeenOpened
CLASS_LOADER_PUBLIC bool hasANonPurePluginLibraryBeenOpened()
Indicates if a library containing more than just plugins has been opened by the running process.
Definition: class_loader_core.cpp:131
class_loader::impl::AbstractMetaObjectBase::setAssociatedLibraryPath
void setAssociatedLibraryPath(std::string library_path)
Sets the path to the library associated with this factory.
Definition: meta_object.cpp:81
class_loader::impl::AbstractMetaObjectBase::isOwnedBy
bool isOwnedBy(const ClassLoader *loader)
Indicates if the factory is within the usable scope of a ClassLoader.
Definition: meta_object.cpp:103
class_loader::impl::isLibraryLoadedByAnybody
CLASS_LOADER_PUBLIC bool isLibraryLoadedByAnybody(const std::string &library_path)
Indicates if passed library has been loaded by ANY ClassLoader.
Definition: class_loader_core.cpp:291
Base
Definition: base.hpp:33
class_loader::impl::getAvailableClasses
std::vector< std::string > getAvailableClasses(ClassLoader *loader)
This function returns all the available class_loader in the plugin system that are derived from Base ...
Definition: class_loader_core.hpp:310
class_loader::impl::BaseClassName
std::string BaseClassName
Definition: class_loader_core.hpp:69
class_loader::impl::getCurrentlyActiveClassLoader
CLASS_LOADER_PUBLIC ClassLoader * getCurrentlyActiveClassLoader()
Gets the ClassLoader currently in scope which used when a library is being loaded.
Definition: class_loader_core.cpp:114
class_loader::impl::LibraryPath
std::string LibraryPath
Definition: class_loader_core.hpp:67
class_loader::ClassLoader
This class allows loading and unloading of dynamically linked libraries which contain class definitio...
Definition: class_loader.hpp:78
class_loader::impl::setCurrentlyLoadingLibraryName
CLASS_LOADER_PUBLIC void setCurrentlyLoadingLibraryName(const std::string &library_name)
When a library is being loaded, in order for factories to know which library they are being associate...
Definition: class_loader_core.cpp:102
class_loader::impl::getLoadedLibraryVectorMutex
CLASS_LOADER_PUBLIC boost::recursive_mutex & getLoadedLibraryVectorMutex()
To provide thread safety, all exposed plugin functions can only be run serially by multiple threads....
Definition: class_loader_core.cpp:50
class_loader::impl::ClassName
std::string ClassName
Definition: class_loader_core.hpp:68
CLASS_LOADER_PUBLIC
#define CLASS_LOADER_PUBLIC
Definition: visibility_control.hpp:58
class_loader::impl::isLibraryLoaded
CLASS_LOADER_PUBLIC bool isLibraryLoaded(const std::string &library_path, ClassLoader *loader)
Indicates if passed library loaded within scope of a ClassLoader. The library maybe loaded in memory,...
Definition: class_loader_core.cpp:306
class_loader::impl::MetaObject
The actual factory. @parm C The derived class (the actual plugin) @parm B The base class interface fo...
Definition: meta_object.hpp:181
visibility_control.hpp
class_loader::impl::getLoadedLibraryVector
CLASS_LOADER_PUBLIC LibraryVector & getLoadedLibraryVector()
Gets a handle to a list of open libraries in the form of LibraryPairs which encode the library path+n...
Definition: class_loader_core.cpp:85
class_loader::impl::BaseToFactoryMapMap
std::map< BaseClassName, FactoryMap > BaseToFactoryMapMap
Definition: class_loader_core.hpp:71
class_loader::impl::getAllLibrariesUsedByClassLoader
CLASS_LOADER_PUBLIC std::vector< std::string > getAllLibrariesUsedByClassLoader(const ClassLoader *loader)
This function returns the names of all libraries in use by a given class loader.
Definition: class_loader_core.cpp:319
class_loader::impl::FactoryMap
std::map< ClassName, impl::AbstractMetaObjectBase * > FactoryMap
Definition: class_loader_core.hpp:70
class_loader::impl::unloadLibrary
CLASS_LOADER_PUBLIC void unloadLibrary(const std::string &library_path, ClassLoader *loader)
Unloads a library if it loaded in memory and cleans up its corresponding class factories....
Definition: class_loader_core.cpp:521
meta_object.hpp
class_loader::CreateClassException
An exception class thrown when class_loader is unable to create a plugin.
Definition: exceptions.hpp:81
class_loader::impl::printDebugInfoToScreen
CLASS_LOADER_PUBLIC void printDebugInfoToScreen()
Definition: class_loader_core.cpp:580
class_loader::impl::setCurrentlyActiveClassLoader
CLASS_LOADER_PUBLIC void setCurrentlyActiveClassLoader(ClassLoader *loader)
Sets the ClassLoader currently in scope which used when a library is being loaded.
Definition: class_loader_core.cpp:119


class_loader
Author(s): Mirza Shah, Steven! Ragnarök
autogenerated on Sun Apr 27 2025 03:01:10