| The Gaudi Framework v32r1 (f65d50dc)

PluginServiceV2.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * (c) Copyright 2013 CERN *
3 * *
4 * This software is distributed under the terms of the GNU General Public *
5 * Licence version 3 (GPL Version 3), copied verbatim in the file "LICENCE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \*****************************************************************************/
11
13
14 #define GAUDI_PLUGIN_SERVICE_V2
15 #include <Gaudi/PluginService.h>
16
17 #include <dirent.h>
18 #include <dlfcn.h>
19
20 #include <cstdlib>
21 #include <fstream>
22 #include <iostream>
23 #include <memory>
24 #include <regex>
25
26 #include <cxxabi.h>
27 #include <sys/stat.h>
28
29 #ifdef _GNU_SOURCE
30 # include <cstring>
31 # include <dlfcn.h>
32 #endif
33
34 #ifdef USE_BOOST_FILESYSTEM
35 # include <boost/filesystem.hpp>
36 namespace fs = boost::filesystem;
37 #else
38 # include <filesystem>
39 namespace fs = std::filesystem;
40 #endif // USE_BOOST_FILESYSTEM
41
42 #if __cplusplus >= 201703
43 # include <string_view>
44 #else
45 # include <experimental/string_view>
46 namespace std {
47 using experimental::string_view;
48 }
49 #endif
50
51 #define REG_SCOPE_LOCK std::lock_guard<std::recursive_mutex> _guard( m_mutex );
52
53 namespace {
54 std::mutex registrySingletonMutex;
55 }
56 #define SINGLETON_LOCK std::lock_guard<std::mutex> _guard( ::registrySingletonMutex );
57
58 #include <algorithm>
59
60 namespace {
61 struct OldStyleCnv {
62 std::string name;
63 void operator()( const char c ) {
64 switch ( c ) {
65 case '<':
66 case '>':
67 case ',':
68 case '(':
69 case ')':
70 case ':':
71 case '.':
72 name.push_back( '_' );
73 break;
74 case '&':
75 name.push_back( 'r' );
76 break;
77 case '*':
78 name.push_back( 'p' );
79 break;
80 case ' ':
81 break;
82 default:
83 name.push_back( c );
84 break;
85 }
86 }
87 };
89 std::string old_style_name( const std::string& name ) {
90 return std::for_each( name.begin(), name.end(), OldStyleCnv() ).name;
91 }
92 } // namespace
93
94 namespace Gaudi {
95 namespace PluginService {
96 GAUDI_PLUGIN_SERVICE_V2_INLINE namespace v2 {
97 namespace Details {
98 std::string demangle( const std::string& id ) {
99 int status;
100 auto realname = std::unique_ptr<char, decltype( free )*>(
101 abi::__cxa_demangle( id.c_str(), nullptr, nullptr, &status ), free );
102 if ( !realname ) return id;
103 #if _GLIBCXX_USE_CXX11_ABI
104 return std::regex_replace(
105 realname.get(),
106 std::regex{"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >( (?=>))?"},
107 "std::string" );
108 #else
109 return std::string{realname.get()};
110 #endif
111 }
112 std::string demangle( const std::type_info& id ) { return demangle( id.name() ); }
113
114 Registry& Registry::instance() {
115 SINGLETON_LOCK
116 static Registry r;
117 return r;
118 }
119
120 void reportBadAnyCast( const std::type_info& factory_type, const std::string& id ) {
121 if ( logger().level() <= Logger::Debug ) {
122 std::stringstream msg;
123 const auto& info = Registry::instance().getInfo( id );
124 msg << "bad any_cast: requested factory " << id << " of type " << demangle( factory_type ) << ", got ";
125 if ( info.is_set() )
126 msg << demangle( info.factory.type() ) << " from " << info.library;
127 else
128 msg << "nothing";
129 logger().debug( msg.str() );
130 }
131 }
132
133 Registry::Properties::mapped_type Registry::FactoryInfo::getprop( const Properties::key_type& name ) const {
134 auto p = properties.find( name );
135 return ( p != end( properties ) ) ? p->second : Properties::mapped_type{};
136 }
137
138 Registry::Registry() {}
139
140 void Registry::initialize() {
141 REG_SCOPE_LOCK
142 #if defined( _WIN32 )
143 const char* envVar = "PATH";
144 const char sep = ';';
145 #elif defined( __APPLE__ )
146 const char* envVar = "DYLD_LIBRARY_PATH";
147 const char sep = ':';
148 #else
149 const char* envVar = "LD_LIBRARY_PATH";
150 const char sep = ':';
151 #endif
152
153 std::regex line_format{"^(?:[[:space:]]*(?:(v[0-9]+)::)?([^:]+):(.*[^[:space:]]))?[[:space:]]*(?:#.*)?$"};
154 std::smatch m;
155
156 std::string_view search_path = std::getenv( envVar );
157 if ( !search_path.empty() ) {
158 logger().debug( std::string( "searching factories in " ) + envVar );
159
160 std::string_view::size_type start_pos = 0, end_pos = 0;
161 while ( start_pos != std::string_view::npos ) {
162 // correctly handle begin of string or path separator
163 if ( start_pos ) ++start_pos;
164
165 end_pos = search_path.find( sep, start_pos );
166 fs::path dirName =
167 #ifdef USE_BOOST_FILESYSTEM
168 std::string{search_path.substr( start_pos, end_pos - start_pos )};
169 #else
170 search_path.substr( start_pos, end_pos - start_pos );
171 #endif
172 start_pos = end_pos;
173
174 logger().debug( " looking into " + dirName.string() );
175 // look for files called "*.components" in the directory
176 if ( is_directory( dirName ) ) {
177 for ( auto& p : fs::directory_iterator( dirName ) ) {
178 if ( p.path().extension() == ".components" && is_regular_file( p.path() ) ) {
179 // read the file
180 const auto& fullPath = p.path().string();
181 logger().debug( " reading " + p.path().filename().string() );
182 std::ifstream factories{fullPath};
183 std::string line;
184 int factoriesCount = 0;
185 int lineCount = 0;
186 while ( !factories.eof() ) {
187 ++lineCount;
188 std::getline( factories, line );
189 if ( regex_match( line, m, line_format ) ) {
190 if ( m[1] == "v2" ) { // ignore non "v2" and "empty" lines
191 const std::string lib{m[2]};
192 const std::string fact{m[3]};
193 m_factories.emplace( fact, FactoryInfo{lib, {}, {{"ClassName", fact}}} );
194 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
195 // add an alias for the factory using the Reflex convention
196 std::string old_name = old_style_name( fact );
197 if ( fact != old_name ) {
198 m_factories.emplace( old_name,
199 FactoryInfo{lib, {}, {{"ReflexName", "true"}, {"ClassName", fact}}} );
200 }
201 #endif
202 ++factoriesCount;
203 }
204 } else {
205 logger().warning( "failed to parse line " + fullPath + ':' + std::to_string( lineCount ) );
206 }
207 }
208 if ( logger().level() <= Logger::Debug ) {
209 logger().debug( " found " + std::to_string( factoriesCount ) + " factories" );
210 }
211 }
212 }
213 }
214 }
215 }
216 }
217
218 const Registry::FactoryMap& Registry::factories() const {
219 std::call_once( m_initialized, &Registry::initialize, const_cast<Registry*>( this ) );
220 return m_factories;
221 }
222
223 Registry::FactoryMap& Registry::factories() {
224 std::call_once( m_initialized, &Registry::initialize, this );
225 return m_factories;
226 }
227
228 Registry::FactoryInfo& Registry::add( const KeyType& id, FactoryInfo info ) {
229 REG_SCOPE_LOCK
230 FactoryMap& facts = factories();
231
232 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
233 // add an alias for the factory using the Reflex convention
234 const auto old_name = old_style_name( id );
235 if ( id != old_name ) {
236 auto new_info = info;
237
238 new_info.properties["ReflexName"] = "true";
239
240 add( old_name, new_info );
241 }
242 #endif
243
244 auto entry = facts.find( id );
245 if ( entry == facts.end() ) {
246 // this factory was not known yet
247 entry = facts.emplace( id, std::move( info ) ).first;
248 } else {
249 // do not replace an existing factory with a new one
250 if ( !entry->second.is_set() ) entry->second = std::move( info );
251 }
252 return entry->second;
253 }
254
255 const Registry::FactoryInfo& Registry::getInfo( const KeyType& id, const bool load ) const {
256 REG_SCOPE_LOCK
257 static const FactoryInfo unknown = {"unknown"};
258 const FactoryMap& facts = factories();
259 auto f = facts.find( id );
260
261 if ( f != facts.end() ) {
262 if ( load && !f->second.is_set() ) {
263 const std::string library = f->second.library;
264 if ( !dlopen( library.c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
265 logger().warning( "cannot load " + library + " for factory " + id );
266 char* dlmsg = dlerror();
267 if ( dlmsg ) logger().warning( dlmsg );
268 return unknown;
269 }
270 f = facts.find( id ); // ensure that the iterator is valid
271 }
272 return f->second;
273 } else {
274 return unknown;
275 }
276 }
277
278 Registry& Registry::addProperty( const KeyType& id, const KeyType& k, const std::string& v ) {
279 REG_SCOPE_LOCK
280 FactoryMap& facts = factories();
281 auto f = facts.find( id );
282
283 if ( f != facts.end() ) f->second.properties[k] = v;
284 return *this;
285 }
286
287 std::set<Registry::KeyType> Registry::loadedFactoryNames() const {
288 REG_SCOPE_LOCK
289 std::set<KeyType> l;
290 for ( const auto& f : factories() ) {
291 if ( f.second.is_set() ) l.insert( f.first );
292 }
293 return l;
294 }
295
296 void Logger::report( Level lvl, const std::string& msg ) {
297 static const char* levels[] = {"DEBUG : ", "INFO : ", "WARNING: ", "ERROR : "};
298 if ( lvl >= level() ) { std::cerr << levels[lvl] << msg << std::endl; }
299 }
300
301 static auto s_logger = std::make_unique<Logger>();
302 Logger& logger() { return *s_logger; }
303 void setLogger( Logger* logger ) { s_logger.reset( logger ); }
304
305 // This chunk of code was taken from GaudiKernel (genconf) DsoUtils.h
306 std::string getDSONameFor( void* fptr ) {
307 #ifdef _GNU_SOURCE
308 Dl_info info;
309 if ( dladdr( fptr, &info ) == 0 ) return "";
310
311 auto pos = std::strrchr( info.dli_fname, '/' );
312 if ( pos )
313 ++pos;
314 else
315 return info.dli_fname;
316 return pos;
317 #else
318 return "";
319 #endif
320 }
321 } // namespace Details
322
323 void SetDebug( int debugLevel ) {
324 using namespace Details;
325 Logger& l = logger();
326 if ( debugLevel > 1 )
327 l.setLevel( Logger::Debug );
328 else if ( debugLevel > 0 )
329 l.setLevel( Logger::Info );
330 else
331 l.setLevel( Logger::Warning );
332 }
333
334 int Debug() {
335 using namespace Details;
336 switch ( logger().level() ) {
337 case Logger::Debug:
338 return 2;
339 case Logger::Info:
340 return 1;
341 default:
342 return 0;
343 }
344 }
345 }
346 } // namespace PluginService
347 } // namespace Gaudi
std::regex_match
T regex_match(T... args)
gaudirun.c
c
Definition: gaudirun.py:487
GaudiPython.HistoUtils.path
path
Definition: HistoUtils.py:932
gaudiComponentHelp.name
name
Definition: gaudiComponentHelp.py:41
GAUDI_PLUGIN_SERVICE_V2_INLINE
#define GAUDI_PLUGIN_SERVICE_V2_INLINE
Definition: PluginServiceCommon.h:17
std::getline
T getline(T... args)
std::to_string
T to_string(T... args)
std::endl
T endl(T... args)
std
STL namespace.
Gaudi::PluginService::v2::SetDebug
void SetDebug(int debugLevel)
Definition: PluginServiceV2.cpp:323
std::call_once
T call_once(T... args)
std::stringstream
STL class.
std::mutex
Gaudi::PluginService::v2::Details::getDSONameFor
std::string getDSONameFor(void *fptr)
Definition: PluginServiceV2.cpp:306
Gaudi::PluginService::v2::Details::reportBadAnyCast
void reportBadAnyCast(const std::type_info &factory_type, const std::string &id)
Definition: PluginServiceV2.cpp:120
std::type_info
std::string
STL class.
std::getenv
T getenv(T... args)
GaudiPython.Persistency.add
def add(instance)
Definition: Persistency.py:39
MSG::Level
Level
Definition: IMessageSvc.h:15
std::regex_replace
T regex_replace(T... args)
Gaudi::Units::m
constexpr double m
Definition: SystemOfUnits.h:92
REG_SCOPE_LOCK
#define REG_SCOPE_LOCK
Definition: PluginServiceV2.cpp:51
IOTest.end
def end
Definition: IOTest.py:112
std::smatch
Gaudi::PluginService::v2::Details::setLogger
void setLogger(Logger *logger)
Definition: PluginServiceV2.cpp:303
std::strrchr
T strrchr(T... args)
std::move
T move(T... args)
gaudirun.l
dictionary l
Definition: gaudirun.py:521
PluginService.h
std::set
STL class.
std::unique_ptr
STL class.
gaudiComponentHelp.properties
properties
Definition: gaudiComponentHelp.py:51
std::regex
std::string::c_str
T c_str(T... args)
GaudiMP.FdsRegistry.msg
msg
Definition: FdsRegistry.py:8
GaudiPluginService.cpluginsvc.factories
def factories()
Definition: cpluginsvc.py:81
std::string::substr
T substr(T... args)
Gaudi::PluginService::v2::Details::logger
Logger & logger()
Definition: PluginServiceV2.cpp:302
Gaudi::PluginService::v2::Details::demangle
std::string demangle(const std::string &id)
Definition: PluginServiceV2.cpp:98
gaudirun.level
level
Definition: gaudirun.py:334
SINGLETON_LOCK
#define SINGLETON_LOCK
Definition: PluginServiceV2.cpp:56
std::for_each
T for_each(T... args)
std::cerr
Gaudi
Header file for std:chrono::duration-based Counters.
Definition: __init__.py:1
Gaudi::PluginService::v2::Debug
int Debug()
Definition: PluginServiceV2.cpp:334
std::ifstream
STL class.
plotSpeedupsPyRoot.line
line
Definition: plotSpeedupsPyRoot.py:170