| The Gaudi Framework v28r2p1 (f1a77ff4)

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