Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:14:59

0001 /*****************************************************************************\
0002 * (c) Copyright 2013 CERN                                                     *
0003 *                                                                             *
0004 * This software is distributed under the terms of the GNU General Public      *
0005 * Licence version 3 (GPL Version 3), copied verbatim in the file "LICENCE".   *
0006 *                                                                             *
0007 * In applying this licence, CERN does not waive the privileges and immunities *
0008 * granted to it by virtue of its status as an Intergovernmental Organization  *
0009 * or submit itself to any jurisdiction.                                       *
0010 \*****************************************************************************/
0011 
0012 /// @author Marco Clemencic <marco.clemencic@cern.ch>
0013 
0014 #define GAUDI_PLUGIN_SERVICE_V2
0015 #include <Gaudi/PluginService.h>
0016 
0017 #include <boost/algorithm/string.hpp>
0018 
0019 #include <dirent.h>
0020 #include <dlfcn.h>
0021 
0022 #include <cstdlib>
0023 #include <fstream>
0024 #include <iostream>
0025 #include <memory>
0026 #include <regex>
0027 #include <vector>
0028 
0029 #include <cxxabi.h>
0030 #include <sys/stat.h>
0031 
0032 #ifdef _GNU_SOURCE
0033 #  include <cstring>
0034 #  include <dlfcn.h>
0035 #endif
0036 
0037 #ifdef USE_BOOST_FILESYSTEM
0038 #  include <boost/filesystem.hpp>
0039 namespace fs = boost::filesystem;
0040 #else
0041 #  include <filesystem>
0042 namespace fs = std::filesystem;
0043 #endif // USE_BOOST_FILESYSTEM
0044 
0045 #if __cplusplus >= 201703 || (__clang__ && __APPLE__)
0046 #  include <string_view>
0047 #else
0048 #  include <experimental/string_view>
0049 namespace std {
0050   using experimental::string_view;
0051 }
0052 #endif
0053 
0054 #define REG_SCOPE_LOCK std::lock_guard<std::recursive_mutex> _guard( m_mutex );
0055 
0056 namespace {
0057   std::mutex registrySingletonMutex;
0058 }
0059 #define SINGLETON_LOCK std::lock_guard<std::mutex> _guard( ::registrySingletonMutex );
0060 
0061 #include <algorithm>
0062 
0063 namespace {
0064   struct OldStyleCnv {
0065     std::string name;
0066     void        operator()( const char c ) {
0067       switch ( c ) {
0068       case '<':
0069       case '>':
0070       case ',':
0071       case '(':
0072       case ')':
0073       case ':':
0074       case '.':
0075         name.push_back( '_' );
0076         break;
0077       case '&':
0078         name.push_back( 'r' );
0079         break;
0080       case '*':
0081         name.push_back( 'p' );
0082         break;
0083       case ' ':
0084         break;
0085       default:
0086         name.push_back( c );
0087         break;
0088       }
0089     }
0090   };
0091   /// Convert a class name in the string used with the Reflex plugin service
0092   std::string old_style_name( const std::string& name ) {
0093     return std::for_each( name.begin(), name.end(), OldStyleCnv() ).name;
0094   }
0095 } // namespace
0096 
0097 namespace Gaudi {
0098   namespace PluginService {
0099     GAUDI_PLUGIN_SERVICE_V2_INLINE namespace v2 {
0100       namespace Details {
0101         std::string demangle( const std::string& id ) {
0102           int  status;
0103           auto realname = std::unique_ptr<char, decltype( free )*>(
0104               abi::__cxa_demangle( id.c_str(), nullptr, nullptr, &status ), free );
0105           if ( !realname ) return id;
0106 #if _GLIBCXX_USE_CXX11_ABI
0107           return std::regex_replace(
0108               realname.get(),
0109               std::regex{"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >( (?=>))?"},
0110               "std::string" );
0111 #else
0112           return std::string{realname.get()};
0113 #endif
0114         }
0115         std::string demangle( const std::type_info& id ) { return demangle( id.name() ); }
0116 
0117         Registry& Registry::instance() {
0118           SINGLETON_LOCK
0119           static Registry r;
0120           return r;
0121         }
0122 
0123         void reportBadAnyCast( const std::type_info& factory_type, const std::string& id ) {
0124           if ( logger().level() <= Logger::Debug ) {
0125             std::stringstream msg;
0126             const auto&       info = Registry::instance().getInfo( id );
0127             msg << "bad any_cast: requested factory " << id << " of type " << demangle( factory_type ) << ", got ";
0128             if ( info.is_set() )
0129               msg << demangle( info.factory.type() ) << " from " << info.library;
0130             else
0131               msg << "nothing";
0132             logger().debug( msg.str() );
0133           }
0134         }
0135 
0136         Registry::Properties::mapped_type Registry::FactoryInfo::getprop( const Properties::key_type& name ) const {
0137           auto p = properties.find( name );
0138           return ( p != end( properties ) ) ? p->second : Properties::mapped_type{};
0139         }
0140 
0141         Registry::Registry() {}
0142 
0143         void Registry::initialize() {
0144           REG_SCOPE_LOCK
0145 #if defined( _WIN32 )
0146           const std::string envVar = "PATH";
0147           const std::string sep    = ";";
0148 #elif defined( __APPLE__ )
0149           const std::string envVar = "DYLD_LIBRARY_PATH";
0150           const std::string sep    = ":";
0151 #else
0152           const std::string envVar = "LD_LIBRARY_PATH";
0153           const std::string sep    = ":";
0154 #endif
0155 
0156           std::regex  line_format{"^(?:[[:space:]]*(?:(v[0-9]+)::)?([^:]+):(.*[^[:space:]]))?[[:space:]]*(?:#.*)?$"};
0157           std::smatch matches;
0158 
0159           std::string search_path;
0160           const char* envPtr = std::getenv( envVar.c_str() );
0161           if ( envPtr ) search_path = envPtr;
0162           if ( search_path.empty() ) {
0163             return;
0164           }
0165 
0166           logger().debug("searching factories in " + envVar);
0167           logger().debug("searching factories in " + search_path);
0168 
0169           std::vector<std::string> directories;
0170           boost::split(directories, search_path, boost::is_any_of(sep));
0171 
0172           for(fs::path dirName: directories) {
0173             if ( not is_directory( dirName ) ) {
0174               continue;
0175             }
0176             logger().debug( " looking into " + dirName.string() );
0177             for ( auto& p : fs::directory_iterator( dirName ) ) {
0178               // look for files called "*.components" in the directory
0179               if ( p.path().extension() == ".components" && is_regular_file( p.path() ) ) {
0180                 // read the file
0181                 const auto& fullPath = p.path().string();
0182                 logger().debug( "  reading " + p.path().filename().string() );
0183                 std::ifstream factories{fullPath};
0184                 std::string   line;
0185                 int           factoriesCount = 0;
0186                 int           lineCount      = 0;
0187                 while ( !factories.eof() ) {
0188                   ++lineCount;
0189                   std::getline( factories, line );
0190                   if ( regex_match( line, matches, line_format ) ) {
0191                     if ( matches[1] == "v2" ) { // ignore non "v2" and "empty" lines
0192                       const std::string lib{matches[2]};
0193                       const std::string fact{matches[3]};
0194                       m_factories.emplace( fact, FactoryInfo{lib, {}, {{"ClassName", fact}}} );
0195 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
0196                       // add an alias for the factory using the Reflex convention
0197                       std::string old_name = old_style_name( fact );
0198                       if ( fact != old_name ) {
0199                         m_factories.emplace( old_name,
0200                                              FactoryInfo{lib, {}, {{"ReflexName", "true"}, {"ClassName", fact}}} );
0201                       }
0202 #endif
0203                       ++factoriesCount;
0204                     }
0205                   } else {
0206                     logger().debug( "failed to parse line " + fullPath + ':' + std::to_string( lineCount ) );
0207                   }
0208                 }
0209                 if ( logger().level() <= Logger::Debug ) {
0210                   logger().debug( "  found " + std::to_string( factoriesCount ) + " factories" );
0211                 }
0212               }
0213             }
0214           }
0215         }
0216 
0217         const Registry::FactoryMap& Registry::factories() const {
0218           std::call_once( m_initialized, &Registry::initialize, const_cast<Registry*>( this ) );
0219           return m_factories;
0220         }
0221 
0222         Registry::FactoryMap& Registry::factories() {
0223           std::call_once( m_initialized, &Registry::initialize, this );
0224           return m_factories;
0225         }
0226 
0227         Registry::FactoryInfo& Registry::add( const KeyType& id, FactoryInfo info ) {
0228           REG_SCOPE_LOCK
0229           FactoryMap& facts = factories();
0230 
0231 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
0232           // add an alias for the factory using the Reflex convention
0233           const auto old_name = old_style_name( id );
0234           if ( id != old_name ) {
0235             auto new_info = info;
0236 
0237             new_info.properties["ReflexName"] = "true";
0238 
0239             add( old_name, new_info );
0240           }
0241 #endif
0242 
0243           auto entry = facts.find( id );
0244           if ( entry == facts.end() ) {
0245             // this factory was not known yet
0246             entry = facts.emplace( id, std::move( info ) ).first;
0247           } else {
0248             // do not replace an existing factory with a new one
0249             if ( !entry->second.is_set() ) entry->second = std::move( info );
0250           }
0251           return entry->second;
0252         }
0253 
0254         const Registry::FactoryInfo& Registry::getInfo( const KeyType& id, const bool load ) const {
0255           REG_SCOPE_LOCK
0256           static const FactoryInfo unknown = {"unknown"};
0257           const FactoryMap&        facts   = factories();
0258           auto                     f       = facts.find( id );
0259 
0260           if ( f != facts.end() ) {
0261             if ( load && !f->second.is_set() ) {
0262               const std::string library = f->second.library;
0263               if ( !dlopen( library.c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
0264                 logger().warning( "cannot load " + library + " for factory " + id );
0265                 char* dlmsg = dlerror();
0266                 if ( dlmsg ) logger().warning( dlmsg );
0267                 return unknown;
0268               }
0269               f = facts.find( id ); // ensure that the iterator is valid
0270             }
0271             return f->second;
0272           } else {
0273             return unknown;
0274           }
0275         }
0276 
0277         Registry& Registry::addProperty( const KeyType& id, const KeyType& k, const std::string& v ) {
0278           REG_SCOPE_LOCK
0279           FactoryMap& facts = factories();
0280           auto        f     = facts.find( id );
0281 
0282           if ( f != facts.end() ) f->second.properties[k] = v;
0283           return *this;
0284         }
0285 
0286         std::set<Registry::KeyType> Registry::loadedFactoryNames() const {
0287           REG_SCOPE_LOCK
0288           std::set<KeyType> l;
0289           for ( const auto& f : factories() ) {
0290             if ( f.second.is_set() ) l.insert( f.first );
0291           }
0292           return l;
0293         }
0294 
0295         void Logger::report( Level lvl, const std::string& msg ) {
0296           static const char* levels[] = {"DEBUG  : ", "INFO   : ", "WARNING: ", "ERROR  : "};
0297           if ( lvl >= level() ) { std::cerr << levels[lvl] << msg << std::endl; }
0298         }
0299 
0300         static auto s_logger = std::make_unique<Logger>();
0301         Logger&     logger() { return *s_logger; }
0302         void        setLogger( Logger* logger ) { s_logger.reset( logger ); }
0303 
0304         // This chunk of code was taken from GaudiKernel (genconf) DsoUtils.h
0305         std::string getDSONameFor( void* fptr ) {
0306 #ifdef _GNU_SOURCE
0307           Dl_info info;
0308           if ( dladdr( fptr, &info ) == 0 ) return "";
0309 
0310           auto pos = std::strrchr( info.dli_fname, '/' );
0311           if ( pos )
0312             ++pos;
0313           else
0314             return info.dli_fname;
0315           return pos;
0316 #else
0317           return "";
0318 #endif
0319         }
0320       } // namespace Details
0321 
0322       void SetDebug( int debugLevel ) {
0323         using namespace Details;
0324         Logger& l = logger();
0325         if ( debugLevel > 1 )
0326           l.setLevel( Logger::Debug );
0327         else if ( debugLevel > 0 )
0328           l.setLevel( Logger::Info );
0329         else
0330           l.setLevel( Logger::Warning );
0331       }
0332 
0333       int Debug() {
0334         using namespace Details;
0335         switch ( logger().level() ) {
0336         case Logger::Debug:
0337           return 2;
0338         case Logger::Info:
0339           return 1;
0340         default:
0341           return 0;
0342         }
0343       }
0344     }
0345   } // namespace PluginService
0346 } // namespace Gaudi