| The Gaudi Framework v30r0 (c919700c)

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

- File List
- File Members

System.cpp
Go to the documentation of this file.
1 //====================================================================
2 // System.cpp
3 //--------------------------------------------------------------------
4 //
5 // Package : System (The LHCb System service)
6 //
7 // Description: Implementation of Systems internals
8 //
9 // Author : M.Frank
10 // Created : 13/1/99
11 // Changes :
12 //====================================================================
13 #define SYSTEM_SYSTEM_CPP
14 #include <algorithm>
15 #include <array>
16 #include <cstdlib>
17 #include <cstring>
18 #include <ctime>
19 #include <iomanip>
20 #include <iostream>
21 #include <memory>
22 #include <regex>
23 #include <sstream>
24 #include <typeinfo>
25
26 #include "GaudiKernel/System.h"
27
28 // Platform specific include(s):
29 #ifdef __linux__
30 #include "Platform/SystemLinux.h"
31 #elif defined( __APPLE__ )
32 #include "Platform/SystemMacOS.h"
33 #elif defined( _WIN32 )
34 #include "Platform/SystemWin32.h"
35 #endif
36
37 #define VCL_NAMESPACE Gaudi
38 #include "instrset_detect.cpp"
39 #undef VCL_NAMESPACE
40
41 #ifdef _WIN32
42 #define strcasecmp _stricmp
43 #define strncasecmp _strnicmp
44 #define getpid _getpid
45 #define NOMSG
46 #define NOGDI
47 #include "process.h"
48 #include "windows.h"
49 #undef NOMSG
50 #undef NOGDI
51 static const std::array<const char*, 1> SHLIB_SUFFIXES = {".dll"};
52 #else // UNIX...: first the EGCS stuff, then the OS dependent includes
53 #include "libgen.h"
54 #include "sys/times.h"
55 #include "unistd.h"
56 #include <cstdio>
57 #include <cxxabi.h>
58 #include <errno.h>
59 #include <string.h>
60 #if defined( __linux ) || defined( __APPLE__ )
61 #include "dlfcn.h"
62 #include <sys/utsname.h>
63 #include <unistd.h>
64 #elif __hpux
65 #include "dl.h"
66 struct HMODULE {
67 shl_descriptor dsc;
68 long numSym;
69 shl_symbol* sym;
70 };
71 #endif // HPUX or not...
72
73 #ifdef __APPLE__
74 static const std::array<const char*, 2> SHLIB_SUFFIXES = {".dylib", ".so"};
75 #else
76 static const std::array<const char*, 1> SHLIB_SUFFIXES = {".so"};
77 #endif // __APPLE__
78
79 #endif // Windows or Unix...
80
81 // Note: __attribute__ is a GCC keyword available since GCC 3.4
82 #ifdef __GNUC__
83 #if __GNUC__ < 3 || ( __GNUC__ == 3 && ( __GNUC_MINOR__ < 4 ) )
84 // GCC < 3.4
85 #define __attribute__( x )
86 #endif
87 #else
88 // non-GCC
89 #define __attribute__( x )
90 #endif
91
92 static unsigned long doLoad( const std::string& name, System::ImageHandle* handle )
93 {
94 #ifdef _WIN32
95 void* mh = ::LoadLibrary( name.length() == 0 ? System::exeName().c_str() : name.c_str() );
96 *handle = mh;
97 #else
98 const char* path = name.c_str();
99 #if defined( __linux ) || defined( __APPLE__ )
100 void* mh = ::dlopen( name.length() == 0 ? nullptr : path, RTLD_LAZY | RTLD_GLOBAL );
101 *handle = mh;
102 #elif __hpux
103 shl_t mh = ::shl_load( name.length() == 0 ? 0 : path, BIND_IMMEDIATE | BIND_VERBOSE, 0 );
104 HMODULE* mod = new HMODULE;
105 if ( 0 != mh ) {
106 if ( 0 != ::shl_gethandle_r( mh, &mod->dsc ) ) {
107 std::cout << "System::loadDynamicLib>" << ::strerror( getLastError() ) << std::endl;
108 } else {
109 typedef void* ( *___all )();
110 ___all _alloc = (___all)malloc;
111 mod->numSym = ::shl_getsymbols( mod->dsc.handle, TYPE_PROCEDURE, EXPORT_SYMBOLS, malloc, &mod->sym );
112 *handle = mod;
113 }
114 }
115 #endif
116 #endif
117 if ( !*handle ) {
118 return System::getLastError();
119 }
120 return 1;
121 }
122
123 static unsigned long loadWithoutEnvironment( const std::string& name, System::ImageHandle* handle )
124 {
125
126 // If the name is empty, don't do anything complicated.
127 if ( name.length() == 0 ) {
128 return doLoad( name, handle );
129 }
130
131 // Check if the specified name has a shared library suffix already. If it
132 // does, don't bother the name any more.
133 std::string dllName = name;
134 bool hasShlibSuffix = false;
135 for ( const char* suffix : SHLIB_SUFFIXES ) {
136 const size_t len = strlen( suffix );
137 if ( dllName.compare( dllName.length() - len, len, suffix ) == 0 ) {
138 hasShlibSuffix = true;
139 break;
140 }
141 }
142
143 // If it doesn't have a shared library suffix on it, add the "default" shared
144 // library suffix to the name.
145 if ( !hasShlibSuffix ) {
146 dllName += SHLIB_SUFFIXES[0];
147 }
148
149 // Load the library.
150 return doLoad( dllName, handle );
151 }
152
154 unsigned long System::loadDynamicLib( const std::string& name, ImageHandle* handle )
155 {
156 unsigned long res = 0;
157 // if name is empty, just load it
158 if ( name.length() == 0 ) {
159 res = loadWithoutEnvironment( name, handle );
160 } else {
161 // If the name is a logical name (environment variable), the try
162 // to load the corresponding library from there.
163 std::string imgName;
164 if ( getEnv( name, imgName ) ) {
165 res = loadWithoutEnvironment( imgName, handle );
166 } else {
167 // build the dll name
168 std::string dllName = name;
169 // Add a possible "lib" prefix to the name on unix platforms. But only if
170 // it's not an absolute path name.
171 #if defined( __linux ) || defined( __APPLE__ )
172 if ( ( dllName.find( '/' ) == std::string::npos ) && ( dllName.compare( 0, 3, "lib" ) != 0 ) ) {
173 dllName = "lib" + dllName;
174 }
175 #endif // unix
176 // Now try loading the library with all possible suffixes supported by the
177 // platform.
178 for ( const char* suffix : SHLIB_SUFFIXES ) {
179 // Add the suffix if necessary.
180 std::string libName = dllName;
181 const size_t len = strlen( suffix );
182 if ( dllName.compare( dllName.length() - len, len, suffix ) != 0 ) {
183 libName += suffix;
184 }
185 // Try to load the library.
186 res = loadWithoutEnvironment( libName, handle );
187 // If the load succeeded, stop here.
188 if ( res == 1 ) {
189 break;
190 }
191 }
192 }
193 if ( res != 1 ) {
194 #if defined( __linux ) || defined( __APPLE__ )
195 errno = 0xAFFEDEAD;
196 #endif
197 // std::cout << "System::loadDynamicLib>" << getLastErrorString() << std::endl;
198 }
199 }
200 return res;
201 }
202
204 unsigned long System::unloadDynamicLib( ImageHandle handle )
205 {
206 #ifdef _WIN32
207 if ( !::FreeLibrary( (HINSTANCE)handle ) ) {
208 #elif defined( __linux ) || defined( __APPLE__ )
209 ::dlclose( handle );
210 if ( 0 ) {
211 #elif __hpux
212 // On HP we have to run finalization ourselves.....
213 Creator pFinalize = 0;
214 if ( getProcedureByName( handle, "_fini", &pFinalize ) ) {
215 pFinalize();
216 }
217 HMODULE* mod = (HMODULE*)handle;
218 if ( 0 == ::shl_unload( mod->dsc.handle ) ) {
219 delete mod;
220 } else {
221 #else
222 if ( false ) {
223 #endif
224 return getLastError();
225 }
226 return 1;
227 }
228
230 unsigned long System::getProcedureByName( ImageHandle handle, const std::string& name, EntryPoint* pFunction )
231 {
232 #ifdef _WIN32
233 *pFunction = ( EntryPoint )::GetProcAddress( (HINSTANCE)handle, name.data() );
234 if ( 0 == *pFunction ) {
235 return System::getLastError();
236 }
237 return 1;
238 #elif defined( __linux )
239 #if __GNUC__ < 4
240 *pFunction = ( EntryPoint )::dlsym( handle, name.c_str() );
241 #else
242 *pFunction = FuncPtrCast<EntryPoint>(::dlsym( handle, name.c_str() ) );
243 #endif
244 if ( !*pFunction ) {
245 errno = 0xAFFEDEAD;
246 // std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
247 return 0;
248 }
249 return 1;
250 #elif defined( __APPLE__ )
251 *pFunction = ( EntryPoint )::dlsym( handle, name.c_str() );
252 if ( !( *pFunction ) ) {
253 // Try with an underscore :
254 std::string sname = "_" + name;
255 *pFunction = ( EntryPoint )::dlsym( handle, sname.c_str() );
256 }
257 if ( 0 == *pFunction ) {
258 errno = 0xAFFEDEAD;
259 std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
260 // std::cout << "System::getProcedureByName> failure" << std::endl;
261 return 0;
262 }
263 return 1;
264 #elif __hpux
265 HMODULE* mod = (HMODULE*)handle;
266 if ( 0 != mod ) {
267 long ll1 = name.length();
268 for ( int i = 0; i < mod->numSym; i++ ) {
269 long ll2 = strlen( mod->sym[i].name );
270 if ( 0 != ::strncmp( mod->sym[i].name, name.c_str(), ( ll1 > ll2 ) ? ll1 : ll2 ) == 0 ) {
271 *pFunction = (EntryPoint)mod->sym[i].value;
272 return 1;
273 }
274 }
275 }
276 return 0;
277 #endif
278 }
279
281 unsigned long System::getProcedureByName( ImageHandle handle, const std::string& name, Creator* pFunction )
282 {
283 return getProcedureByName( handle, name, (EntryPoint*)pFunction );
284 }
285
287 unsigned long System::getLastError()
288 {
289 #ifdef _WIN32
290 return ::GetLastError();
291 #else
292 // convert errno (int) to unsigned long
293 return static_cast<unsigned long>( static_cast<unsigned int>( errno ) );
294 #endif
295 }
296
298 const std::string System::getLastErrorString()
299 {
300 const std::string errString = getErrorString( getLastError() );
301 return errString;
302 }
303
305 const std::string System::getErrorString( unsigned long error )
306 {
307 std::string errString = "";
308 #ifdef _WIN32
309 LPVOID lpMessageBuffer;
310 ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error,
311 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // The user default language
312 (LPTSTR)&lpMessageBuffer, 0, NULL );
313 errString = (const char*)lpMessageBuffer;
314 // Free the buffer allocated by the system
315 ::LocalFree( lpMessageBuffer );
316 #else
317 char* cerrString( nullptr );
318 // Remember: for linux dl* routines must be handled differently!
319 if ( error == 0xAFFEDEAD ) {
320 cerrString = (char*)::dlerror();
321 if ( !cerrString ) cerrString = ::strerror( error );
322 if ( !cerrString ) {
323 cerrString = (char*)"Unknown error. No information found in strerror()!";
324 } else {
325 errString = std::string( cerrString );
326 }
327 errno = 0;
328 } else {
329 cerrString = ::strerror( error );
330 errString = std::string( cerrString );
331 }
332 #endif
333 return errString;
334 }
335
336 const std::string System::typeinfoName( const std::type_info& tinfo ) { return typeinfoName( tinfo.name() ); }
337
338 const std::string System::typeinfoName( const char* class_name ) { return Platform::typeinfoName( class_name ); }
339
341 const std::string& System::hostName()
342 {
343 static const std::string host = Platform::hostName();
344 return host;
345 }
346
348 const std::string& System::osName()
349 {
350 static const std::string osname = Platform::osName();
351 return osname;
352 }
353
355 const std::string& System::osVersion()
356 {
357 static const std::string osver = Platform::osVersion();
358 return osver;
359 }
360
362 const std::string& System::machineType()
363 {
364 static const std::string mach = Platform::machineType();
365 return mach;
366 }
367
368 int System::instructionsetLevel()
369 {
370 using namespace Gaudi;
371 return instrset_detect();
372 }
373
375 const std::string& System::accountName()
376 {
377 static const std::string account = Platform::accountName();
378 return account;
379 }
380
382 long System::numCmdLineArgs() { return cmdLineArgs().size(); }
383
385 long System::argc() { return cmdLineArgs().size(); }
386
388 const std::vector<std::string> System::cmdLineArgs()
389 {
390 static const std::vector<std::string> args = Platform::cmdLineArgs();
391 return args;
392 }
393
395 char** System::argv()
396 {
397 auto helperFunc = []( const std::vector<std::string>& args ) -> std::vector<const char*> {
398 std::vector<const char*> result;
399 std::transform( args.begin(), args.end(), std::back_inserter( result ),
400 []( const std::string& s ) { return s.c_str(); } );
401 return result;
402 };
403 static const std::vector<const char*> args = helperFunc( cmdLineArgs() );
404 // We rely here on the fact that a vector's allocation table is contiguous
405 return (char**)&( args[0] );
406 }
407
408 #ifdef WIN32
409 // disable warning
410 // C4996: 'getenv': This function or variable may be unsafe.
411 #pragma warning( disable : 4996 )
412 #endif
413
415 std::string System::getEnv( const char* var )
416 {
417 char* env;
418 if ( ( env = getenv( var ) ) != nullptr ) {
419 return env;
420 } else {
421 return "UNKNOWN";
422 }
423 }
424
426 bool System::getEnv( const char* var, std::string& value )
427 {
428 char* env;
429 if ( ( env = getenv( var ) ) != nullptr ) {
430 value = env;
431 return true;
432 } else {
433 return false;
434 }
435 }
436
437 bool System::isEnvSet( const char* var ) { return getenv( var ) != nullptr; }
438
440 #if defined( __APPLE__ )
441 // Needed for _NSGetEnviron(void)
442 #include "crt_externs.h"
443 #endif
444 std::vector<std::string> System::getEnv()
445 {
446 #if defined( _WIN32 )
447 #define environ _environ
448 #elif defined( __APPLE__ )
449 static char** environ = *_NSGetEnviron();
450 #endif
451 std::vector<std::string> vars;
452 for ( int i = 0; environ[i] != nullptr; ++i ) {
453 vars.push_back( environ[i] );
454 }
455 return vars;
456 }
457
458 // -----------------------------------------------------------------------------
459 // backtrace utilities
460 // -----------------------------------------------------------------------------
461 #ifdef __linux
462 #include <execinfo.h>
463 #endif
464
465 int System::backTrace( void** addresses __attribute__( ( unused ) ), const int depth __attribute__( ( unused ) ) )
466 {
467
468 #ifdef __linux
469
470 int count = backtrace( addresses, depth );
471 return count > 0 ? count : 0;
472
473 #else // windows and osx parts not implemented
474 return 0;
475 #endif
476 }
477
478 bool System::backTrace( std::string& btrace, const int depth, const int offset )
479 {
480 try {
481 // Always hide the first two levels of the stack trace (that's us)
482 const int totalOffset = offset + 2;
483 const int totalDepth = depth + totalOffset;
484
485 std::string fnc, lib;
486
487 std::vector<void*> addresses( totalDepth, nullptr );
488 int count = System::backTrace( addresses.data(), totalDepth );
489 for ( int i = totalOffset; i < count; ++i ) {
490 void* addr = nullptr;
491
492 if ( System::getStackLevel( addresses[i], addr, fnc, lib ) ) {
493 std::ostringstream ost;
494 ost << "#" << std::setw( 3 ) << std::setiosflags( std::ios::left ) << i - totalOffset + 1;
495 ost << std::hex << addr << std::dec << " " << fnc << " [" << lib << "]" << std::endl;
496 btrace += ost.str();
497 }
498 }
499 return true;
500 } catch ( const std::bad_alloc& e ) {
501 return false;
502 }
503 }
504
505 bool System::getStackLevel( void* addresses __attribute__( ( unused ) ), void*& addr __attribute__( ( unused ) ),
506 std::string& fnc __attribute__( ( unused ) ), std::string& lib __attribute__( ( unused ) ) )
507 {
508
509 #ifdef __linux
510
511 Dl_info info;
512
513 if ( dladdr( addresses, &info ) && info.dli_fname && info.dli_fname[0] != '\0' ) {
514 const char* symbol = info.dli_sname && info.dli_sname[0] != '\0' ? info.dli_sname : nullptr;
515
516 lib = info.dli_fname;
517 addr = info.dli_saddr;
518
519 if ( symbol ) {
520 int stat = -1;
521 auto dmg =
522 std::unique_ptr<char, decltype( free )*>( abi::__cxa_demangle( symbol, nullptr, nullptr, &stat ), std::free );
523 fnc = ( stat == 0 ) ? dmg.get() : symbol;
524 } else {
525 fnc = "local";
526 }
527 return true;
528 } else {
529 return false;
530 }
531
532 #else // not implemented for windows and osx
533 return false;
534 #endif
535 }
536
538 int System::setEnv( const std::string& name, const std::string& value, int overwrite )
539 {
540 #ifndef WIN32
541 // UNIX version
542 return value.empty() ?
543 // remove if set to nothing (and return success)
544 ::unsetenv( name.c_str() ),
545 0 :
546 // set the value
547 ::setenv( name.c_str(), value.c_str(), overwrite );
548 #else
549 // Windows version
550 if ( value.empty() ) {
551 // equivalent to unsetenv
552 return ::_putenv( ( name + "=" ).c_str() );
553 } else {
554 if ( !getenv( name.c_str() ) || overwrite ) {
555 // set if not yet present or overwrite is set (force)
556 return ::_putenv( ( name + "=" + value ).c_str() );
557 }
558 }
559 return 0; // if we get here, we are trying to set a variable already set, but
560 // not to overwrite.
561 // It is considered a success on Linux (man P setenv)
562 #endif
563 }
System::getEnv
GAUDI_API std::string getEnv(const char *var)
get a particular environment variable (returning "UNKNOWN" if not set)
Definition: System.cpp:415
System.h
System::argc
GAUDI_API long argc()
Number of arguments passed to the commandline (==numCmdLineArgs()); just to match argv call...
Definition: System.cpp:385
System::argv
GAUDI_API char ** argv()
char** command line arguments including executable name as arg[0]; You may not modify them! ...
Definition: System.cpp:395
__attribute__
#define __attribute__(x)
Definition: System.cpp:89
std::string::empty
T empty(T...args)
System::getErrorString
GAUDI_API const std::string getErrorString(unsigned long error)
Retrieve error code as string for a given error.
Definition: System.cpp:305
System::setEnv
GAUDI_API int setEnv(const std::string &name, const std::string &value, int overwrite=1)
Set an environment variables.
Definition: System.cpp:538
System::getLastError
GAUDI_API unsigned long getLastError()
Get last system known error.
Definition: System.cpp:287
System::getProcedureByName
GAUDI_API unsigned long getProcedureByName(ImageHandle handle, const std::string &name, EntryPoint *pFunction)
Get a specific function defined in the DLL.
Definition: System.cpp:230
GaudiPython.HistoUtils.path
path
Definition: HistoUtils.py:895
gaudiComponentHelp.name
name
Definition: gaudiComponentHelp.py:32
System::getStackLevel
GAUDI_API bool getStackLevel(void *addresses, void *&addr, std::string &fnc, std::string &lib)
System::typeinfoName
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:336
gaudirun.args
args
Definition: gaudirun.py:244
SystemMacOS.h
System::instructionsetLevel
GAUDI_API int instructionsetLevel()
Instruction Set "Level".
Definition: System.cpp:368
Gaudi.CommonGaudiConfigurables.mod
mod
Definition: CommonGaudiConfigurables.py:22
System::accountName
GAUDI_API const std::string & accountName()
User login name.
Definition: System.cpp:375
std::endl
T endl(T...args)
std::free
T free(T...args)
std::setiosflags
T setiosflags(T...args)
System::ImageHandle
void * ImageHandle
Definition of an image handle.
Definition: ModuleInfo.h:31
System::backTrace
GAUDI_API int backTrace(void **addresses, const int depth)
std::setw
T setw(T...args)
std::type_info
std::string
STL class.
System::numCmdLineArgs
GAUDI_API long numCmdLineArgs()
Number of arguments passed to the commandline.
Definition: System.cpp:382
System::exeName
GAUDI_API const std::string & exeName()
Name of the executable file running.
Definition: ModuleInfo.cpp:210
instrset_detect.cpp
std::vector::push_back
T push_back(T...args)
std::string::data
T data(T...args)
std::ostringstream
STL class.
System::osName
GAUDI_API const std::string & osName()
OS name.
Definition: System.cpp:348
instrset_detect
int instrset_detect(void)
Definition: instrset_detect.cpp:101
std::ostringstream::str
T str(T...args)
compareOutputFiles.sname
sname
Definition: compareOutputFiles.py:443
System::unloadDynamicLib
GAUDI_API unsigned long unloadDynamicLib(ImageHandle handle)
unload dynamic link library
Definition: System.cpp:204
System::isEnvSet
GAUDI_API bool isEnvSet(const char *var)
Check if an environment variable is set or not.
Definition: System.cpp:437
std::unique_ptr::get
T get(T...args)
std::string::find
T find(T...args)
std::string::length
T length(T...args)
System::hostName
GAUDI_API const std::string & hostName()
Host name.
Definition: System.cpp:341
System::Creator
void *(* Creator)()
Definition of the "generic" DLL entry point function.
Definition: System.h:38
std::vector< std::string >
std::type_info::name
T name(T...args)
std::unique_ptr
STL class.
std::back_inserter
T back_inserter(T...args)
std::bad_alloc
STL class.
std::string::c_str
T c_str(T...args)
gaudirun.s
string s
Definition: gaudirun.py:253
std::array
STL class.
std::hex
T hex(T...args)
System::cmdLineArgs
GAUDI_API const std::vector< std::string > cmdLineArgs()
Command line arguments including executable name as arg[0] as vector of strings.
Definition: System.cpp:388
System::osVersion
GAUDI_API const std::string & osVersion()
OS version.
Definition: System.cpp:355
std::transform
T transform(T...args)
System::getLastErrorString
GAUDI_API const std::string getLastErrorString()
Get last system error as string.
Definition: System.cpp:298
System::machineType
GAUDI_API const std::string & machineType()
Machine type.
Definition: System.cpp:362
SystemWin32.h
std::cout
SystemLinux.h
Gaudi
Helper functions to set/get the application return code.
Definition: __init__.py:1
std::string::compare
T compare(T...args)
System::loadDynamicLib
GAUDI_API unsigned long loadDynamicLib(const std::string &name, ImageHandle *handle)
Load dynamic link library.
Definition: System.cpp:154
System::EntryPoint
unsigned long(* EntryPoint)(const unsigned long iid, void **ppvObject)
Definition of the "generic" DLL entry point function.
Definition: System.h:36