Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "rve_pluginloader/plugin.h"
00031 #include "rve_pluginloader/type_registry.h"
00032
00033 #include <iostream>
00034 #include <fstream>
00035 #include <yaml-cpp/yaml.h>
00036
00037 #include <ros/assert.h>
00038 #include <ros/package.h>
00039 #include <ros/debug.h>
00040
00041 #include <boost/filesystem.hpp>
00042
00043 namespace fs = boost::filesystem;
00044
00045 namespace rve_pluginloader
00046 {
00047
00048 Plugin::Plugin()
00049 : loaded_(false)
00050 , doc_(0)
00051 {
00052
00053 }
00054
00055 Plugin::~Plugin()
00056 {
00057 unload(false);
00058
00059 delete doc_;
00060 }
00061
00062 void Plugin::loadDescription(const std::string& description_path)
00063 {
00064 description_path_ = description_path;
00065
00066 std::ifstream fin(description_path.c_str());
00067
00068 try
00069 {
00070 YAML::Parser parser(fin);
00071 doc_ = new YAML::Node;
00072 YAML::Node& doc = *doc_;
00073 parser.GetNextDocument(doc);
00074
00075 std::string library;
00076 doc["library"] >> library;
00077
00078 fs::path p(description_path);
00079 fs::path parent = p.parent_path();
00080
00081 while (true)
00082 {
00083 if (fs::exists(parent / "manifest.xml"))
00084 {
00085 std::string package = parent.filename();
00086 std::string package_path = ros::package::getPath(package);
00087 if (description_path.find(package_path) == 0)
00088 {
00089 package_name_ = package;
00090 package_path_ = package_path;
00091 break;
00092 }
00093 }
00094
00095 parent = parent.parent_path();
00096
00097 if (parent.string().empty())
00098 {
00099 ROS_ERROR("Could not find package name for plugin [%s]", description_path.c_str());
00100 break;
00101 }
00102 }
00103
00104 std::string library_dir = (fs::path(package_path_) / (fs::path(library).parent_path())).string();
00105 std::string library_name = fs::path(library).filename();
00106 library_path_ = (fs::path(library_dir) / fs::path(rve_dynlib::prefix() + library_name + rve_dynlib::suffix())).string();
00107
00108 doc["name"] >> name_;
00109 }
00110 catch (YAML::ParserException& e)
00111 {
00112 throw PluginParseException(description_path, e.msg);
00113 }
00114 catch (YAML::RepresentationException& e)
00115 {
00116 throw PluginParseException(description_path, e.msg);
00117 }
00118 }
00119
00120 void Plugin::load()
00121 {
00122 if (loaded_)
00123 {
00124 return;
00125 }
00126
00127 loading_signal_(PluginStatus(this));
00128
00129 if (!fs::exists(library_path_))
00130 {
00131 throw LibraryDoesNotExistException(library_path_);
00132 }
00133
00134 try
00135 {
00136 library_ = rve_dynlib::load(library_path_);
00137 }
00138 catch (rve_dynlib::LibraryLoadException& e)
00139 {
00140 throw LibraryLoadException(library_path_, e.what());
00141 }
00142
00143 if (!rve_dynlib::hasSymbol(library_, "rvePluginRegister"))
00144 {
00145 throw NoPluginRegisterFunctionException(library_path_);
00146 }
00147
00148 typedef void (*RegisterFunc)(TypeRegistry*);
00149 RegisterFunc init = reinterpret_cast<RegisterFunc>(rve_dynlib::getSymbol(library_, "rvePluginRegister"));
00150
00151 TypeRegistry reg(package_name_);
00152 (*init)(®);
00153
00154 class_entries_ = reg.getClassEntries();
00155
00156 loaded_ = true;
00157 loaded_signal_(PluginStatus(this));
00158 }
00159
00160 const V_ClassEntry* Plugin::getClassEntries(const std::string& base_class) const
00161 {
00162 M_ClassEntry::const_iterator it = class_entries_.find(base_class);
00163 if (it == class_entries_.end())
00164 {
00165 return 0;
00166 }
00167
00168 return &it->second;
00169 }
00170
00171 void Plugin::unload()
00172 {
00173 unload(true);
00174 }
00175
00176 void Plugin::unload(bool allow_throw)
00177 {
00178 if (!loaded_)
00179 {
00180 return;
00181 }
00182
00183 unloading_signal_(PluginStatus(this));
00184
00185
00186
00187 if (!allocations_.empty())
00188 {
00189 std::stringstream ss;
00190 ss << "Plugin loaded from [" << description_path_ << "] still has outstanding allocations:\n";
00191
00192 M_AllocationInfo::iterator it = allocations_.begin();
00193 M_AllocationInfo::iterator end = allocations_.end();
00194 for (; it != end; ++it)
00195 {
00196 AllocationInfo& info = it->second;
00197 ss << "====================================================\n";
00198 ss << "Base Class: " << info.base_class << "\n";
00199 ss << "Derived Class: " << info.derived_class << "\n";
00200 ss << "Pointer Address: " << info.pointer << "\n";
00201
00202 std::string backtrace = ros::debug::backtraceToString(info.backtrace);
00203 ss << "Allocated from:\n";
00204 ss << backtrace;
00205 }
00206
00207 if (allow_throw)
00208 {
00209 throw OutstandingAllocationException(ss.str());
00210 }
00211 else
00212 {
00213 ROS_ERROR_STREAM(ss.str());
00214 }
00215 }
00216
00217 class_entries_.clear();
00218
00219 rve_dynlib::unload(library_);
00220 loaded_ = false;
00221
00222 unloaded_signal_(PluginStatus(this));
00223 }
00224
00225 bool Plugin::isLoaded()
00226 {
00227 return loaded_;
00228 }
00229
00230 bool Plugin::hasClass(const std::string& base_class, const std::string& derived_class) const
00231 {
00232 try
00233 {
00234 getClassEntry(base_class, derived_class);
00235 }
00236 catch (PluginDoesNotContainClassException&)
00237 {
00238 return false;
00239 }
00240
00241 return true;
00242 }
00243
00244 const ClassEntryPtr& Plugin::getClassEntry(const std::string& base_class, const std::string& derived_class) const
00245 {
00246 M_ClassEntry::const_iterator it = class_entries_.find(base_class);
00247 if (it == class_entries_.end())
00248 {
00249 throw PluginDoesNotContainClassException(package_name_, derived_class);
00250 }
00251
00252 V_ClassEntry::const_iterator lit = it->second.begin();
00253 V_ClassEntry::const_iterator lend = it->second.end();
00254 for (; lit != lend; ++lit)
00255 {
00256 const ClassEntryPtr& entry = *lit;
00257 if (entry->class_name == derived_class)
00258 {
00259 return entry;
00260 }
00261 }
00262
00263 throw PluginDoesNotContainClassException(package_name_, derived_class);
00264 }
00265
00266 void* Plugin::create(const std::string& base_class, const std::string& derived_class)
00267 {
00268 const ClassEntryPtr& ent = getClassEntry(base_class, derived_class);
00269 void* mem = ent->creator->create();
00270 AllocationInfo info;
00271 info.base_class = base_class;
00272 info.derived_class = derived_class;
00273 info.pointer = mem;
00274 ros::debug::getBacktrace(info.backtrace);
00275 allocations_.insert(std::make_pair(mem, info));
00276 return mem;
00277 }
00278
00279 struct ClassDeleter
00280 {
00281 ClassDeleter(Plugin* plugin)
00282 : plugin_(plugin)
00283 {}
00284
00285 void operator()(void* mem)
00286 {
00287 plugin_->destroy(mem);
00288 }
00289
00290 Plugin* plugin_;
00291 };
00292
00293 boost::shared_ptr<void> Plugin::createShared(const std::string& base_class, const std::string& derived_class)
00294 {
00295 return boost::shared_ptr<void>(create(base_class, derived_class), ClassDeleter(this));
00296 }
00297
00298 void Plugin::destroy(void* mem)
00299 {
00300 M_AllocationInfo::iterator it = allocations_.find(mem);
00301 ROS_ASSERT(it != allocations_.end());
00302 allocations_.erase(it);
00303 }
00304
00305 bool Plugin::ownsAllocation(void* mem)
00306 {
00307 M_AllocationInfo::iterator it = allocations_.find(mem);
00308 return it != allocations_.end();
00309 }
00310
00311 }