class_loader  master
The class_loader package is a ROS-independent package for loading plugins during runtime.
class_loader.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_HPP_
33 #define CLASS_LOADER__CLASS_LOADER_HPP_
34 
35 #include <algorithm>
36 #include <cassert>
37 #include <cstddef>
38 #include <functional>
39 #include <memory>
40 #include <mutex>
41 #include <string>
42 #include <vector>
43 
44 // TODO(mikaelarguedas) remove this once console_bridge complies with this
45 // see https://github.com/ros/console_bridge/issues/55
46 #ifdef __clang__
47 # pragma clang diagnostic push
48 # pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
49 #endif
50 #include "console_bridge/console.h"
51 #ifdef __clang__
52 # pragma clang diagnostic pop
53 #endif
54 
58 
59 namespace class_loader
60 {
61 
63 
71 std::string systemLibraryFormat(const std::string & library_name);
72 
80 {
81 public:
82  template<typename Base>
83  using DeleterType = std::function<void (Base *)>;
84 
85  template<typename Base>
87 
96  explicit ClassLoader(const std::string & library_path, bool ondemand_load_unload = false);
97 
102  virtual ~ClassLoader();
103 
109  template<class Base>
111  {
112  return class_loader::impl::getAvailableClasses<Base>(this);
113  }
114 
124  template<class Base>
126  {
127  return std::shared_ptr<Base>(
128  createRawInstance<Base>(derived_class_name, true),
129  std::bind(&ClassLoader::onPluginDeletion<Base>, this, std::placeholders::_1)
130  );
131  }
132 
134 
146  template<class Base>
148  {
149  Base * raw = createRawInstance<Base>(derived_class_name, true);
151  raw,
152  std::bind(&ClassLoader::onPluginDeletion<Base>, this, std::placeholders::_1)
153  );
154  }
155 
157 
169  template<class Base>
170  Base * createUnmanagedInstance(const std::string & derived_class_name)
171  {
172  return createRawInstance<Base>(derived_class_name, false);
173  }
174 
182  template<class Base>
183  bool isClassAvailable(const std::string & class_name) const
184  {
185  std::vector<std::string> available_classes = getAvailableClasses<Base>();
186  return std::find(
187  available_classes.begin(), available_classes.end(), class_name) != available_classes.end();
188  }
189 
196  const std::string & getLibraryPath() const;
197 
209  bool isLibraryLoaded() const;
210 
218  bool isLibraryLoadedByAnyClassloader() const;
219 
228  bool isOnDemandLoadUnloadEnabled() const;
229 
237  void loadLibrary();
238 
253  int unloadLibrary();
254 
255 private:
261  template<class Base>
262  void onPluginDeletion(Base * obj)
263  {
264  CONSOLE_BRIDGE_logDebug(
265  "class_loader::ClassLoader: Calling onPluginDeletion() for obj ptr = %p.\n",
266  reinterpret_cast<void *>(obj));
267  if (nullptr == obj) {
268  return;
269  }
270  std::lock_guard<std::recursive_mutex> lock(plugin_ref_count_mutex_);
271  delete (obj);
272  assert(plugin_ref_count_ > 0);
273  --plugin_ref_count_;
274  if (plugin_ref_count_ == 0 && isOnDemandLoadUnloadEnabled()) {
275  if (!ClassLoader::hasUnmanagedInstanceBeenCreated()) {
276  unloadLibraryInternal(false);
277  } else {
278  CONSOLE_BRIDGE_logWarn(
279  "class_loader::ClassLoader: "
280  "Cannot unload library %s even though last shared pointer went out of scope. "
281  "This is because createUnmanagedInstance was used within the scope of this process, "
282  "perhaps by a different ClassLoader. "
283  "Library will NOT be closed.",
284  getLibraryPath().c_str());
285  }
286  }
287  }
288 
290 
302  template<class Base>
303  Base * createRawInstance(const std::string & derived_class_name, bool managed)
304  {
305  if (!managed) {
306  this->setUnmanagedInstanceBeenCreated(true);
307  }
308 
309  if (
310  managed &&
311  ClassLoader::hasUnmanagedInstanceBeenCreated() &&
313  {
314  CONSOLE_BRIDGE_logInform(
315  "%s",
316  "class_loader::ClassLoader: "
317  "An attempt is being made to create a managed plugin instance (i.e. boost::shared_ptr), "
318  "however an unmanaged instance was created within this process address space. "
319  "This means libraries for the managed instances will not be shutdown automatically on "
320  "final plugin destruction if on demand (lazy) loading/unloading mode is used."
321  );
322  }
323  if (!isLibraryLoaded()) {
324  loadLibrary();
325  }
326 
327  Base * obj = class_loader::impl::createInstance<Base>(derived_class_name, this);
328  assert(obj != NULL); // Unreachable assertion if createInstance() throws on failure.
329 
330  if (managed) {
331  std::lock_guard<std::recursive_mutex> lock(plugin_ref_count_mutex_);
332  ++plugin_ref_count_;
333  }
334 
335  return obj;
336  }
337 
342  static bool hasUnmanagedInstanceBeenCreated();
343 
345  static void setUnmanagedInstanceBeenCreated(bool state);
346 
358  int unloadLibraryInternal(bool lock_plugin_ref_count);
359 
360 private:
361  bool ondemand_load_unload_;
362  std::string library_path_;
363  int load_ref_count_;
364  std::recursive_mutex load_ref_count_mutex_;
365  int plugin_ref_count_;
366  std::recursive_mutex plugin_ref_count_mutex_;
367  static bool has_unmananged_instance_been_created_;
368 };
369 
370 } // namespace class_loader
371 
372 
373 #endif // CLASS_LOADER__CLASS_LOADER_HPP_
class_loader::ClassLoader::~ClassLoader
virtual ~ClassLoader()
Destructor for ClassLoader. All libraries opened by this ClassLoader are unloaded automatically.
std::lock
T lock(T... args)
class_loader::ClassLoader::isOnDemandLoadUnloadEnabled
bool isOnDemandLoadUnloadEnabled() const
Indicates if the library is to be loaded/unloaded on demand...meaning that only to load a lib when th...
std::bind
T bind(T... args)
std::string
std::shared_ptr
class_loader
Definition: class_loader.hpp:59
class_loader::ClassLoader::createUnmanagedInstance
Base * createUnmanagedInstance(const std::string &derived_class_name)
Generates an instance of loadable classes (i.e. class_loader).
Definition: class_loader.hpp:170
std::vector
std::find
T find(T... args)
class_loader::systemLibraryFormat
std::string systemLibraryFormat(const std::string &library_name)
Returns a platform specific version of a basic library name.
class_loader::ClassLoader::createInstance
std::shared_ptr< Base > createInstance(const std::string &derived_class_name)
Generates an instance of loadable classes (i.e. class_loader).
Definition: class_loader.hpp:125
std::recursive_mutex
std::lock_guard
class_loader::ClassLoader::isLibraryLoadedByAnyClassloader
bool isLibraryLoadedByAnyClassloader() const
Indicates if a library is loaded by some entity in the plugin system (another ClassLoader),...
class_loader_core.hpp
std::function
class_loader::ClassLoader::getLibraryPath
const std::string & getLibraryPath() const
Gets the full-qualified path and name of the library associated with this class loader.
class_loader::ClassLoader::getAvailableClasses
std::vector< std::string > getAvailableClasses() const
Indicates which classes (i.e. class_loader) that can be loaded by this object.
Definition: class_loader.hpp:110
class_loader::ClassLoader::isClassAvailable
bool isClassAvailable(const std::string &class_name) const
Indicates if a plugin class is available.
Definition: class_loader.hpp:183
class_loader::ClassLoader::loadLibrary
void loadLibrary()
Attempts to load a library on behalf of the ClassLoader. If the library is already opened,...
class_loader::ClassLoader::unloadLibrary
int unloadLibrary()
Attempts to unload a library loaded within scope of the ClassLoader. If the library is not opened,...
class_loader::ClassLoader
This class allows loading and unloading of dynamically linked libraries which contain class definitio...
Definition: class_loader.hpp:79
CLASS_LOADER_PUBLIC
#define CLASS_LOADER_PUBLIC
Definition: visibility_control.hpp:58
class_loader::ClassLoader::createUniqueInstance
UniquePtr< Base > createUniqueInstance(const std::string &derived_class_name)
Generates an instance of loadable classes (i.e. class_loader).
Definition: class_loader.hpp:147
std::vector::begin
T begin(T... args)
visibility_control.hpp
std::vector::end
T end(T... args)
register_macro.hpp
std::unique_ptr
class_loader::ClassLoader::ClassLoader
ClassLoader(const std::string &library_path, bool ondemand_load_unload=false)
Constructor for ClassLoader.
class_loader::ClassLoader::isLibraryLoaded
bool isLibraryLoaded() const
Indicates if a library is loaded within the scope of this ClassLoader.