class_loader.h
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2012, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 #ifndef CLASS_LOADER__CLASS_LOADER_H_
00031 #define CLASS_LOADER__CLASS_LOADER_H_
00032 
00033 #include <boost/bind.hpp>
00034 #include <boost/shared_ptr.hpp>
00035 #include <boost/thread/recursive_mutex.hpp>
00036 #include <string>
00037 #include <vector>
00038 
00039 #include "console_bridge/console.h"
00040 
00041 #include "class_loader/class_loader_core.h"
00042 #include "class_loader/class_loader_register_macro.h"
00043 #include "class_loader/console_bridge_compatibility.h"
00044 
00045 #if __cplusplus >= 201103L
00046 #include <memory>
00047 #include <functional>
00048 #endif
00049 
00050 // TODO(mikaelarguedas) : replace no lints with the explicit keyword in an ABI breaking release
00051 
00052 namespace class_loader
00053 {
00054 
00058 std::string systemLibrarySuffix();
00059 
00064 class ClassLoader
00065 {
00066 public:
00067 #if __cplusplus >= 201103L
00068   template<typename Base>
00069   using DeleterType = std::function<void(Base *)>;
00070 
00071   template<typename Base>
00072   using UniquePtr = std::unique_ptr<Base, DeleterType<Base>>;
00073 #endif
00074 
00080   ClassLoader(const std::string & library_path, bool ondemand_load_unload = false);  // NOLINT
00081 
00085   virtual ~ClassLoader();
00086 
00091   template<class Base>
00092   std::vector<std::string> getAvailableClasses()
00093   {
00094     return class_loader::class_loader_private::getAvailableClasses<Base>(this);
00095   }
00096 
00100   std::string getLibraryPath() {return library_path_;}
00101 
00111   template<class Base>
00112   boost::shared_ptr<Base> createInstance(const std::string & derived_class_name)
00113   {
00114     return boost::shared_ptr<Base>(
00115       createRawInstance<Base>(derived_class_name, true),
00116       boost::bind(&ClassLoader::onPluginDeletion<Base>, this, _1));
00117   }
00118 
00119 #if __cplusplus >= 201103L
00120 
00132   template<class Base>
00133   UniquePtr<Base> createUniqueInstance(const std::string & derived_class_name)
00134   {
00135     Base * raw = createRawInstance<Base>(derived_class_name, true);
00136     return std::unique_ptr<Base, DeleterType<Base>>(
00137       raw,
00138       boost::bind(&ClassLoader::onPluginDeletion<Base>, this, _1));
00139   }
00140 #endif
00141 
00154   template<class Base>
00155   Base * createUnmanagedInstance(const std::string & derived_class_name)
00156   {
00157     return createRawInstance<Base>(derived_class_name, false);
00158   }
00159 
00166   template<class Base>
00167   bool isClassAvailable(const std::string & class_name)
00168   {
00169     std::vector<std::string> available_classes = getAvailableClasses<Base>();
00170     return std::find(
00171       available_classes.begin(), available_classes.end(), class_name) != available_classes.end();
00172   }
00173 
00179   bool isLibraryLoaded();
00180 
00185   bool isLibraryLoadedByAnyClassloader();
00186 
00190   bool isOnDemandLoadUnloadEnabled() {return ondemand_load_unload_;}
00191 
00196   void loadLibrary();
00197 
00202   int unloadLibrary();
00203 
00204 private:
00209   template<class Base>
00210   void onPluginDeletion(Base * obj)
00211   {
00212     CONSOLE_BRIDGE_logDebug(
00213       "class_loader::ClassLoader: Calling onPluginDeletion() for obj ptr = %p.\n", obj);
00214     if (obj) {
00215       boost::recursive_mutex::scoped_lock lock(plugin_ref_count_mutex_);
00216       delete (obj);
00217       plugin_ref_count_ = plugin_ref_count_ - 1;
00218       assert(plugin_ref_count_ >= 0);
00219       if (0 == plugin_ref_count_ && isOnDemandLoadUnloadEnabled()) {
00220         if (!ClassLoader::hasUnmanagedInstanceBeenCreated()) {
00221           unloadLibraryInternal(false);
00222         } else {
00223           CONSOLE_BRIDGE_logWarn(
00224             "class_loader::ClassLoader: "
00225             "Cannot unload library %s even though last shared pointer went out of scope. "
00226             "This is because createUnmanagedInstance was used within the scope of this process,"
00227             " perhaps by a different ClassLoader. Library will NOT be closed.",
00228             getLibraryPath().c_str());
00229         }
00230       }
00231     }
00232   }
00233 
00244   template<class Base>
00245   Base * createRawInstance(const std::string & derived_class_name, bool managed)
00246   {
00247     if (!managed) {
00248       has_unmananged_instance_been_created_ = true;
00249     }
00250 
00251     if (
00252       managed &&
00253       ClassLoader::hasUnmanagedInstanceBeenCreated() &&
00254       isOnDemandLoadUnloadEnabled())
00255     {
00256       CONSOLE_BRIDGE_logInform("%s",
00257         "class_loader::ClassLoader: "
00258         "An attempt is being made to create a managed plugin instance (i.e. boost::shared_ptr), "
00259         "however an unmanaged instance was created within this process address space. "
00260         "This means libraries for the managed instances will not be shutdown automatically on "
00261         "final plugin destruction if on demand (lazy) loading/unloading mode is used."
00262       );
00263     }
00264     if (!isLibraryLoaded()) {
00265       loadLibrary();
00266     }
00267 
00268     Base * obj =
00269       class_loader::class_loader_private::createInstance<Base>(derived_class_name, this);
00270     assert(obj != NULL);  // Unreachable assertion if createInstance() throws on failure
00271 
00272     if (managed) {
00273       boost::recursive_mutex::scoped_lock lock(plugin_ref_count_mutex_);
00274       plugin_ref_count_ = plugin_ref_count_ + 1;
00275     }
00276 
00277     return obj;
00278   }
00279 
00283   static bool hasUnmanagedInstanceBeenCreated();
00284 
00290   int unloadLibraryInternal(bool lock_plugin_ref_count);
00291 
00292 private:
00293   bool ondemand_load_unload_;
00294   std::string library_path_;
00295   int load_ref_count_;
00296   boost::recursive_mutex load_ref_count_mutex_;
00297   int plugin_ref_count_;
00298   boost::recursive_mutex plugin_ref_count_mutex_;
00299   static bool has_unmananged_instance_been_created_;
00300 };
00301 
00302 }  // namespace class_loader
00303 
00304 
00305 #endif  // CLASS_LOADER__CLASS_LOADER_H_


class_loader
Author(s): Mirza Shah
autogenerated on Thu Dec 7 2017 04:48:01