📄 pionplugin.cpp
字号:
// -----------------------------------------------------------------// libpion: a C++ framework for building lightweight HTTP interfaces// -----------------------------------------------------------------// Copyright (C) 2007 Atomic Labs, Inc. (http://www.atomiclabs.com)//// Distributed under the Boost Software License, Version 1.0.// See accompanying file COPYING or copy at http://www.boost.org/LICENSE_1_0.txt//#include <libpion/PionConfig.hpp>#include <libpion/PionPlugin.hpp>#include <boost/filesystem/operations.hpp>#ifdef PION_WIN32 #include <windows.h>#else #include <dlfcn.h>#endifnamespace pion { // begin namespace pion // static members of PionEngine const std::string PionPlugin::PION_PLUGIN_CREATE("pion_create_");const std::string PionPlugin::PION_PLUGIN_DESTROY("pion_destroy_");#ifdef PION_WIN32 const std::string PionPlugin::PION_PLUGIN_EXTENSION(".dll");#else const std::string PionPlugin::PION_PLUGIN_EXTENSION(".so");#endifconst std::string PionPlugin::PION_CONFIG_EXTENSION(".conf");std::vector<std::string> PionPlugin::m_plugin_dirs;PionPlugin::PluginMap PionPlugin::m_plugin_map;boost::mutex PionPlugin::m_plugin_mutex; // PionEngine member functions void PionPlugin::checkCygwinPath(boost::filesystem::path& final_path, const std::string& start_path){#if defined(PION_WIN32) && defined(PION_CYGWIN_DIRECTORY) // try prepending PION_CYGWIN_DIRECTORY if not complete if (! final_path.is_complete() && final_path.has_root_directory()) { final_path = boost::filesystem::path(std::string(PION_CYGWIN_DIRECTORY) + start_path); }#endif}void PionPlugin::addPluginDirectory(const std::string& dir){#ifdef PION_WIN32 // work around bug in boost::filesystem on Windows -> do not plugin directories // basically, if you create a path object on Windows, then convert it to // directory_string() or file_string(), then try to construct // a new path object based on the string, it throws an exception (ugh!!!) boost::mutex::scoped_lock plugin_lock(m_plugin_mutex); m_plugin_dirs.push_back(dir);#else boost::filesystem::path plugin_path(dir); checkCygwinPath(plugin_path, dir); if (! boost::filesystem::exists(plugin_path) ) throw DirectoryNotFoundException(dir); boost::mutex::scoped_lock plugin_lock(m_plugin_mutex); m_plugin_dirs.push_back(plugin_path.directory_string());#endif}void PionPlugin::resetPluginDirectories(void){ boost::mutex::scoped_lock plugin_lock(m_plugin_mutex); m_plugin_dirs.clear();}void PionPlugin::open(const std::string& plugin_file){ releaseData(); // make sure we're not already pointing to something // use a temporary object first since openPlugin() may throw PionPluginData plugin_data(getPluginName(plugin_file)); // check to see if we already have a matching shared library boost::mutex::scoped_lock plugin_lock(m_plugin_mutex); PluginMap::iterator itr = m_plugin_map.find(plugin_data.m_plugin_name); if (itr == m_plugin_map.end()) { // no plug-ins found with the same name // open up the shared library using our temporary data object openPlugin(plugin_file, plugin_data); // may throw // all is good -> insert it into the plug-in map m_plugin_data = new PionPluginData(plugin_data); m_plugin_map.insert( std::make_pair(m_plugin_data->m_plugin_name, m_plugin_data) ); } else { // found an existing plug-in with the same name m_plugin_data = itr->second; } // increment the number of references ++ m_plugin_data->m_references;}void PionPlugin::releaseData(void){ if (m_plugin_data != NULL) { boost::mutex::scoped_lock plugin_lock(m_plugin_mutex); // double-check after locking mutex if (m_plugin_data != NULL && --m_plugin_data->m_references == 0) {// The handling of dynamic libraries on Windows is EXTREMELY buggy, so if// we are running on Windows, never release the shared libraries#ifndef PION_WIN32 // no more references to the plug-in library // release the shared object closeDynamicLibrary(m_plugin_data->m_lib_handle); // remove it from the plug-in map PluginMap::iterator itr = m_plugin_map.find(m_plugin_data->m_plugin_name); // check itr just to be safe (it SHOULD always find a match) if (itr != m_plugin_map.end()) m_plugin_map.erase(itr); // release the heap object delete m_plugin_data;#endif } m_plugin_data = NULL; }}void PionPlugin::grabData(const PionPlugin& p){ releaseData(); // make sure we're not already pointing to something boost::mutex::scoped_lock plugin_lock(m_plugin_mutex); m_plugin_data = const_cast<PionPluginData*>(p.m_plugin_data); if (m_plugin_data != NULL) { ++ m_plugin_data->m_references; }}bool PionPlugin::findFile(std::string& path_to_file, const std::string& name, const std::string& extension){ // first, try the name as-is if (checkForFile(path_to_file, name, "", extension)) return true; // nope, check search paths boost::mutex::scoped_lock plugin_lock(m_plugin_mutex); for (std::vector<std::string>::iterator i = m_plugin_dirs.begin(); i != m_plugin_dirs.end(); ++i) { if (checkForFile(path_to_file, *i, name, extension)) return true; } // no plug-in file found return false;}bool PionPlugin::checkForFile(std::string& final_path, const std::string& start_path, const std::string& name, const std::string& extension){ // check for cygwin path oddities boost::filesystem::path cygwin_safe_path(start_path); checkCygwinPath(cygwin_safe_path, start_path); boost::filesystem::path test_path(cygwin_safe_path); // if a name is specified, append it to the test path if (! name.empty()) test_path /= name; // check for existence of plug-in (without extension) if (boost::filesystem::exists(test_path)) { final_path = test_path.file_string(); return true; } // next, try appending the plug-in extension if (name.empty()) { // no "name" specified -> append it directly to start_path test_path = boost::filesystem::path(start_path + extension); // in this case, we need to re-check for the cygwin oddities checkCygwinPath(test_path, start_path + extension); } else { // name is specified, so we can just re-use cygwin_safe_path test_path = cygwin_safe_path / boost::filesystem::path(name + extension); } // re-check for existence of plug-in (after adding extension) if (boost::filesystem::exists(test_path)) { final_path = test_path.file_string(); return true; } // no plug-in file found return false;}void PionPlugin::openPlugin(const std::string& plugin_file, PionPluginData& plugin_data){ // get the name of the plugin (for create/destroy symbol names) plugin_data.m_plugin_name = getPluginName(plugin_file); // attempt to open the plugin; note that this tries all search paths // and also tries a variety of platform-specific extensions plugin_data.m_lib_handle = loadDynamicLibrary(plugin_file.c_str()); if (plugin_data.m_lib_handle == NULL) throw PluginNotFoundException(plugin_file); // find the function used to create new plugin objects plugin_data.m_create_func = getLibrarySymbol(plugin_data.m_lib_handle, PION_PLUGIN_CREATE + plugin_data.m_plugin_name); if (plugin_data.m_create_func == NULL) { closeDynamicLibrary(plugin_data.m_lib_handle); throw PluginMissingCreateException(plugin_file); } // find the function used to destroy existing plugin objects plugin_data.m_destroy_func = getLibrarySymbol(plugin_data.m_lib_handle, PION_PLUGIN_DESTROY + plugin_data.m_plugin_name); if (plugin_data.m_destroy_func == NULL) { closeDynamicLibrary(plugin_data.m_lib_handle); throw PluginMissingDestroyException(plugin_file); }}std::string PionPlugin::getPluginName(const std::string& plugin_file){ // strip path#ifdef PION_WIN32 std::string::size_type pos = plugin_file.find_last_of('\\');#else std::string::size_type pos = plugin_file.find_last_of('/');#endif std::string plugin_name = (pos == std::string::npos ? plugin_file : plugin_file.substr(pos+1)); pos = plugin_name.find('.'); // truncate extension if (pos != std::string::npos) plugin_name.resize(pos); return plugin_name; }void *PionPlugin::loadDynamicLibrary(const std::string& plugin_file){#ifdef PION_WIN32 return LoadLibrary(plugin_file.c_str());#else return dlopen(plugin_file.c_str(), RTLD_LAZY);#endif}void PionPlugin::closeDynamicLibrary(void *lib_handle){#ifdef PION_WIN32 FreeLibrary((HINSTANCE) lib_handle);#else dlclose(lib_handle);#endif}void *PionPlugin::getLibrarySymbol(void *lib_handle, const std::string& symbol){#ifdef PION_WIN32 return (void*)GetProcAddress((HINSTANCE) lib_handle, symbol.c_str());#else return dlsym(lib_handle, symbol.c_str());#endif}} // end namespace pion
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -