| The Gaudi Framework v29r0 (ff2e7097)

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

PluginService.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 #include <Gaudi/PluginService.h>
15
16 #include <dirent.h>
17 #include <dlfcn.h>
18
19 #include <cstdlib>
20 #include <fstream>
21 #include <iostream>
22 #include <memory>
23 #include <regex>
24
25 #include <cxxabi.h>
26 #include <sys/stat.h>
27
28 #if defined( __GXX_EXPERIMENTAL_CXX0X__ ) || __cplusplus >= 201103L
29 #define REG_SCOPE_LOCK std::lock_guard<std::recursive_mutex> _guard( m_mutex );
30
31 namespace
32 {
33 std::mutex registrySingletonMutex;
34 }
35 #define SINGLETON_LOCK std::lock_guard<std::mutex> _guard(::registrySingletonMutex );
36 #else
37 #define REG_SCOPE_LOCK
38 #define SINGLETON_LOCK
39 #endif
40
41 #include <algorithm>
42
43 namespace
44 {
45 // string trimming functions taken from
46 // http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
47
48 constexpr struct is_space_t {
49 bool operator()( int i ) const { return std::isspace( i ); }
50 } is_space{};
51
52 // trim from start
53 static inline std::string& ltrim( std::string& s )
54 {
55 s.erase( s.begin(), std::find_if_not( s.begin(), s.end(), is_space ) );
56 return s;
57 }
58
59 // trim from end
60 static inline std::string& rtrim( std::string& s )
61 {
62 s.erase( std::find_if_not( s.rbegin(), s.rend(), is_space ).base(), s.end() );
63 return s;
64 }
65 // trim from both ends
66 static inline std::string& trim( std::string& s ) { return ltrim( rtrim( s ) ); }
67 }
68
69 namespace
70 {
74 inline void factoryInfoSetHelper( std::string& dest, const std::string value, const std::string& desc,
75 const std::string& id )
76 {
77 if ( dest.empty() ) {
78 dest = value;
79 } else if ( dest != value ) {
80 Gaudi::PluginService::Details::logger().warning( "new factory loaded for '" + id + "' with different " + desc +
81 ": " + dest + " != " + value );
82 }
83 }
84
85 struct OldStyleCnv {
86 std::string name;
87 void operator()( const char c )
88 {
89 switch ( c ) {
90 case '<':
91 case '>':
92 case ',':
93 case '(':
94 case ')':
95 case ':':
96 case '.':
97 name.push_back( '_' );
98 break;
99 case '&':
100 name.push_back( 'r' );
101 break;
102 case '*':
103 name.push_back( 'p' );
104 break;
105 case ' ':
106 break;
107 default:
108 name.push_back( c );
109 break;
110 }
111 }
112 };
114 std::string old_style_name( const std::string& name )
115 {
116 return std::for_each( name.begin(), name.end(), OldStyleCnv() ).name;
117 }
118 }
119
120 namespace Gaudi
121 {
122 namespace PluginService
123 {
124
125 Exception::Exception( std::string msg ) : m_msg( std::move( msg ) ) {}
126 Exception::~Exception() throw() {}
127 const char* Exception::what() const throw() { return m_msg.c_str(); }
128
129 namespace Details
130 {
131 void* getCreator( const std::string& id, const std::string& type )
132 {
133 return Registry::instance().get( id, type );
134 }
135
136 std::string demangle( const std::string& id )
137 {
138 int status;
139 auto realname = std::unique_ptr<char, decltype( free )*>(
140 abi::__cxa_demangle( id.c_str(), nullptr, nullptr, &status ), free );
141 if ( !realname ) return id;
142 #if _GLIBCXX_USE_CXX11_ABI
143 return std::regex_replace(
144 realname.get(),
145 std::regex{"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > ?"},
146 "std::string" );
147 #else
148 return std::string{realname.get()};
149 #endif
150 }
151 std::string demangle( const std::type_info& id ) { return demangle( id.name() ); }
152
153 Registry& Registry::instance()
154 {
155 SINGLETON_LOCK
156 static Registry r;
157 return r;
158 }
159
160 Registry::Registry() : m_initialized( false ) {}
161
162 void Registry::initialize()
163 {
164 REG_SCOPE_LOCK
165 if ( m_initialized ) return;
166 m_initialized = true;
167 #if defined( _WIN32 )
168 const char* envVar = "PATH";
169 const char sep = ';';
170 #elif defined( __APPLE__ )
171 const char* envVar = "DYLD_LIBRARY_PATH";
172 const char sep = ':';
173 #else
174 const char* envVar = "LD_LIBRARY_PATH";
175 const char sep = ':';
176 #endif
177 char* search_path = ::getenv( envVar );
178 if ( search_path ) {
179 logger().debug( std::string( "searching factories in " ) + envVar );
180 std::string path( search_path );
181 std::string::size_type pos = 0;
182 std::string::size_type newpos = 0;
183 while ( pos != std::string::npos ) {
184 std::string dirName;
185 // get the next entry in the path
186 newpos = path.find( sep, pos );
187 if ( newpos != std::string::npos ) {
188 dirName = path.substr( pos, newpos - pos );
189 pos = newpos + 1;
190 } else {
191 dirName = path.substr( pos );
192 pos = newpos;
193 }
194 logger().debug( std::string( " looking into " ) + dirName );
195 // look for files called "*.components" in the directory
196 DIR* dir = opendir( dirName.c_str() );
197 if ( dir ) {
198 struct dirent* entry;
199 while ( ( entry = readdir( dir ) ) ) {
200 std::string name( entry->d_name );
201 // check if the file name ends with ".components"
202 std::string::size_type extpos = name.find( ".components" );
203 if ( ( extpos != std::string::npos ) && ( ( extpos + 11 ) == name.size() ) ) {
204 std::string fullPath = ( dirName + '/' + name );
205 { // check if it is a regular file
206 struct stat buf;
207 stat( fullPath.c_str(), &buf );
208 if ( !S_ISREG( buf.st_mode ) ) continue;
209 }
210 // read the file
211 logger().debug( std::string( " reading " ) + name );
212 std::ifstream factories{fullPath};
213 std::string line;
214 int factoriesCount = 0;
215 int lineCount = 0;
216 while ( !factories.eof() ) {
217 ++lineCount;
218 std::getline( factories, line );
219 trim( line );
220 // skip empty lines and lines starting with '#'
221 if ( line.empty() || line[0] == '#' ) continue;
222 // look for the separator
223 auto pos = line.find( ':' );
224 if ( pos == std::string::npos ) {
225 logger().warning( "failed to parse line " + fullPath + ':' + std::to_string( lineCount ) );
226 continue;
227 }
228 const std::string lib( line, 0, pos );
229 const std::string fact( line, pos + 1 );
230 m_factories.emplace( fact, FactoryInfo( lib ) );
231 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
232 // add an alias for the factory using the Reflex convention
233 std::string old_name = old_style_name( fact );
234 if ( fact != old_name ) {
235 FactoryInfo old_info( lib );
236 old_info.properties["ReflexName"] = "true";
237 m_factories.emplace( old_name, old_info );
238 }
239 #endif
240 ++factoriesCount;
241 }
242 if ( logger().level() <= Logger::Debug ) {
243 logger().debug( " found " + std::to_string( factoriesCount ) + " factories" );
244 }
245 }
246 }
247 closedir( dir );
248 }
249 }
250 }
251 }
252
253 Registry::FactoryInfo& Registry::add( const std::string& id, void* factory, const std::string& type,
254 const std::string& rtype, const std::string& className,
255 const Properties& props )
256 {
257 REG_SCOPE_LOCK
258 FactoryMap& facts = factories();
259 auto entry = facts.find( id );
260 if ( entry == facts.end() ) {
261 // this factory was not known yet
262 entry = facts.emplace( id, FactoryInfo( "unknown", factory, type, rtype, className, props ) ).first;
263 } else {
264 // do not replace an existing factory with a new one
265 if ( !entry->second.ptr ) entry->second.ptr = factory;
266 factoryInfoSetHelper( entry->second.type, type, "type", id );
267 factoryInfoSetHelper( entry->second.rtype, rtype, "return type", id );
268 factoryInfoSetHelper( entry->second.className, className, "class", id );
269 }
270 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
271 // add an alias for the factory using the Reflex convention
272 std::string old_name = old_style_name( id );
273 if ( id != old_name ) add( old_name, factory, type, rtype, className, props ).properties["ReflexName"] = "true";
274 #endif
275 return entry->second;
276 }
277
278 void* Registry::get( const std::string& id, const std::string& type ) const
279 {
280 REG_SCOPE_LOCK
281 const FactoryMap& facts = factories();
282 auto f = facts.find( id );
283 if ( f != facts.end() ) {
284 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
285 const Properties& props = f->second.properties;
286 if ( props.find( "ReflexName" ) != props.end() )
287 logger().warning( "requesting factory via old name '" + id + "'"
288 "use '" +
289 f->second.className + "' instead" );
290 #endif
291 if ( !f->second.ptr ) {
292 if ( !dlopen( f->second.library.c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
293 logger().warning( "cannot load " + f->second.library + " for factory " + id );
294 char* dlmsg = dlerror();
295 if ( dlmsg ) logger().warning( dlmsg );
296 return nullptr;
297 }
298 f = facts.find( id ); // ensure that the iterator is valid
299 }
300 if ( f->second.type == type ) return f->second.ptr;
301 logger().warning( "found factory " + id + ", but of wrong type: " + demangle( f->second.type ) +
302 " instead of " + demangle( type ) );
303 }
304 return nullptr; // factory not found
305 }
306
307 const Registry::FactoryInfo& Registry::getInfo( const std::string& id ) const
308 {
309 REG_SCOPE_LOCK
310 static const FactoryInfo unknown( "unknown" );
311 const FactoryMap& facts = factories();
312 auto f = facts.find( id );
313 return ( f != facts.end() ) ? f->second : unknown;
314 }
315
316 Registry& Registry::addProperty( const std::string& id, const std::string& k, const std::string& v )
317 {
318 REG_SCOPE_LOCK
319 FactoryMap& facts = factories();
320 auto f = facts.find( id );
321 if ( f != facts.end() ) f->second.properties[k] = v;
322 return *this;
323 }
324
325 std::set<Registry::KeyType> Registry::loadedFactories() const
326 {
327 REG_SCOPE_LOCK
328 const FactoryMap& facts = factories();
329 std::set<KeyType> l;
330 for ( const auto& f : facts ) {
331 if ( f.second.ptr ) l.insert( f.first );
332 }
333 return l;
334 }
335
336 void Logger::report( Level lvl, const std::string& msg )
337 {
338 static const char* levels[] = {"DEBUG : ", "INFO : ", "WARNING: ", "ERROR : "};
339 if ( lvl >= level() ) {
340 std::cerr << levels[lvl] << msg << std::endl;
341 }
342 }
343
344 static std::unique_ptr<Logger> s_logger( new Logger );
345 Logger& logger() { return *s_logger; }
346 void setLogger( Logger* logger ) { s_logger.reset( logger ); }
347
348 } // namespace Details
349
350 void SetDebug( int debugLevel )
351 {
352 using namespace Details;
353 Logger& l = logger();
354 if ( debugLevel > 1 )
355 l.setLevel( Logger::Debug );
356 else if ( debugLevel > 0 )
357 l.setLevel( Logger::Info );
358 else
359 l.setLevel( Logger::Warning );
360 }
361
362 int Debug()
363 {
364 using namespace Details;
365 switch ( logger().level() ) {
366 case Logger::Debug:
367 return 2;
368 case Logger::Info:
369 return 1;
370 default:
371 return 0;
372 }
373 }
374 }
375 } // namespace Gaudi::PluginService
Gaudi::PluginService::Details::Logger::Info
Definition: PluginServiceDetails.h:227
std::string::empty
T empty(T...args)
gaudirun.c
c
Definition: gaudirun.py:407
GaudiPython.HistoUtils.path
path
Definition: HistoUtils.py:895
gaudiComponentHelp.name
name
Definition: gaudiComponentHelp.py:32
Gaudi::PluginService::Details::Registry::getInfo
const FactoryInfo & getInfo(const std::string &id) const
Retrieve the FactoryInfo object for an id.
Definition: PluginService.cpp:307
Gaudi::PluginService::Exception::m_msg
std::string m_msg
Definition: PluginService.h:75
std::string::rend
T rend(T...args)
Gaudi::PluginService::Details::Registry::addProperty
Registry & addProperty(const std::string &id, const std::string &k, const std::string &v)
Add a property to an already existing FactoryInfo object (via its id.)
Definition: PluginService.cpp:316
REG_SCOPE_LOCK
#define REG_SCOPE_LOCK
Definition: PluginService.cpp:37
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::Details::Registry::initialize
void initialize()
Initialize the registry loading the list of factories from the .component files in the library search...
Definition: PluginService.cpp:162
std::string::end
T end(T...args)
SINGLETON_LOCK
#define SINGLETON_LOCK
Definition: PluginService.cpp:38
Gaudi::PluginService::Details::Registry::FactoryInfo
Definition: PluginServiceDetails.h:120
std::map< KeyType, std::string >
Gaudi::PluginService::Details::Registry::FactoryInfo::properties
Properties properties
Definition: PluginServiceDetails.h:137
Gaudi::PluginService::Details::Registry::loadedFactories
std::set< KeyType > loadedFactories() const
Return a list of all the known and loaded factories.
Definition: PluginService.cpp:325
std::mutex
Gaudi::PluginService::Details::logger
GAUDIPS_API Logger & logger()
Return the current logger instance.
Definition: PluginService.cpp:345
Gaudi::PluginService::Details::Logger
Simple logging class, just to provide a default implementation.
Definition: PluginServiceDetails.h:224
std::type_info
std::string
STL class.
std::string::push_back
T push_back(T...args)
Gaudi::PluginService::SetDebug
GAUDIPS_API void SetDebug(int debugLevel)
Backward compatibility with Reflex.
Definition: PluginService.cpp:350
Gaudi::PluginService::Details::Registry::get
void * get(const std::string &id, const std::string &type) const
Retrieve the factory for the given id.
Definition: PluginService.cpp:278
std::regex_replace
T regex_replace(T...args)
gaudirun.dest
dest
Definition: gaudirun.py:170
Gaudi::PluginService::Details::demangle
std::string demangle(const std::string &id)
Definition: PluginService.cpp:136
gaudirun.type
type
Definition: gaudirun.py:133
Gaudi::PluginService::Details::demangle
GAUDIPS_API std::string demangle(const std::type_info &id)
Return a canonical name for type_info object (implementation borrowed from GaudiKernel/System).
Definition: PluginService.cpp:151
Gaudi::PluginService::Details::Logger::Level
Level
Definition: PluginServiceDetails.h:227
std::string::erase
T erase(T...args)
Gaudi::PluginService::Details::Registry::factories
const FactoryMap & factories() const
Return the known factories (loading the list if not yet done).
Definition: PluginServiceDetails.h:180
std::unique_ptr::reset
T reset(T...args)
Gaudi::PluginService::Details::Logger::report
virtual void report(Level lvl, const std::string &msg)
Definition: PluginService.cpp:336
Gaudi::PluginService::Details::Logger::warning
void warning(const std::string &msg)
Definition: PluginServiceDetails.h:234
gaudirun.l
dictionary l
Definition: gaudirun.py:440
std::set::insert
T insert(T...args)
PluginService.h
std::find_if_not
T find_if_not(T...args)
std::string::size
T size(T...args)
std::set
STL class.
Gaudi::PluginService::Details::getCreator
GAUDIPS_API void * getCreator(const std::string &id, const std::string &type)
Function used to load a specific factory function.
Definition: PluginService.cpp:131
std::unique_ptr
STL class.
Gaudi::Functional::operator()
virtual Out operator()(const vector_of_const_< In > &inputs) const =0
Gaudi::PluginService::Details::Logger::Warning
Definition: PluginServiceDetails.h:227
std::regex
Gaudi::PluginService::Details::Logger::Debug
Definition: PluginServiceDetails.h:227
std::string::begin
T begin(T...args)
std::string::c_str
T c_str(T...args)
std::map::emplace
T emplace(T...args)
GaudiMP.FdsRegistry.msg
msg
Definition: FdsRegistry.py:8
gaudirun.s
string s
Definition: gaudirun.py:253
Gaudi::PluginService::Details::Registry
In-memory database of the loaded factories.
Definition: PluginServiceDetails.h:112
std::string::substr
T substr(T...args)
Gaudi::PluginService::Details::Registry::add
FactoryInfo & add(const I &id, typename F::FuncType ptr)
Add a factory to the database.
Definition: PluginServiceDetails.h:154
gaudirun.level
level
Definition: gaudirun.py:271
Gaudi::PluginService::Debug
GAUDIPS_API int Debug()
Backward compatibility with Reflex.
Definition: PluginService.cpp:362
Gaudi::PluginService::Details::setLogger
GAUDIPS_API void setLogger(Logger *logger)
Set the logger instance to use.
Definition: PluginService.cpp:346
Gaudi::PluginService::Exception::what
const char * what() const override
Definition: PluginService.cpp:127
std::for_each
T for_each(T...args)
std::cerr
std::isspace
T isspace(T...args)
Gaudi::PluginService::Details::Registry::m_factories
FactoryMap m_factories
Internal storage for factories.
Definition: PluginServiceDetails.h:215
Gaudi
Helper functions to set/get the application return code.
Definition: __init__.py:1
Gaudi::PluginService::Exception::~Exception
~Exception() override
Definition: PluginService.cpp:126
std::ifstream
STL class.
plotSpeedupsPyRoot.line
line
Definition: plotSpeedupsPyRoot.py:172
Gaudi::PluginService::Details::Registry::m_initialized
bool m_initialized
Flag recording if the registry has been initialized or not.
Definition: PluginServiceDetails.h:212
Gaudi::PluginService::Details::Logger::debug
void debug(const std::string &msg)
Definition: PluginServiceDetails.h:233
std::string::rbegin
T rbegin(T...args)