| The Gaudi Framework v32r1 (f65d50dc)

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 static unsigned long doLoad( const std::string& name, System::ImageHandle* handle ) {
82 #ifdef _WIN32
83 void* mh = ::LoadLibrary( name.length() == 0 ? System::exeName().c_str() : name.c_str() );
84 *handle = mh;
85 #else
86 const char* path = name.c_str();
87 # if defined( __linux ) || defined( __APPLE__ )
88 void* mh = ::dlopen( name.length() == 0 ? nullptr : path, RTLD_LAZY | RTLD_GLOBAL );
89 *handle = mh;
90 # elif __hpux
91 shl_t mh = ::shl_load( name.length() == 0 ? 0 : path, BIND_IMMEDIATE | BIND_VERBOSE, 0 );
92 HMODULE* mod = new HMODULE;
93 if ( 0 != mh ) {
94 if ( 0 != ::shl_gethandle_r( mh, &mod->dsc ) ) {
95 std::cout << "System::loadDynamicLib>" << ::strerror( getLastError() ) << std::endl;
96 } else {
97 typedef void* ( *___all )();
98 ___all _alloc = (___all)malloc;
99 mod->numSym = ::shl_getsymbols( mod->dsc.handle, TYPE_PROCEDURE, EXPORT_SYMBOLS, malloc, &mod->sym );
100 *handle = mod;
101 }
102 }
103 # endif
104 #endif
105 if ( !*handle ) { return System::getLastError(); }
106 return 1;
107 }
108
109 static unsigned long loadWithoutEnvironment( const std::string& name, System::ImageHandle* handle ) {
110
111 // If the name is empty, don't do anything complicated.
112 if ( name.length() == 0 ) { return doLoad( name, handle ); }
113
114 // Check if the specified name has a shared library suffix already. If it
115 // does, don't bother the name any more.
116 std::string dllName = name;
117 bool hasShlibSuffix = false;
118 for ( const char* suffix : SHLIB_SUFFIXES ) {
119 const size_t len = strlen( suffix );
120 if ( dllName.compare( dllName.length() - len, len, suffix ) == 0 ) {
121 hasShlibSuffix = true;
122 break;
123 }
124 }
125
126 // If it doesn't have a shared library suffix on it, add the "default" shared
127 // library suffix to the name.
128 if ( !hasShlibSuffix ) { dllName += SHLIB_SUFFIXES[0]; }
129
130 // Load the library.
131 return doLoad( dllName, handle );
132 }
133
135 unsigned long System::loadDynamicLib( const std::string& name, ImageHandle* handle ) {
136 unsigned long res = 0;
137 // if name is empty, just load it
138 if ( name.length() == 0 ) {
139 res = loadWithoutEnvironment( name, handle );
140 } else {
141 // If the name is a logical name (environment variable), the try
142 // to load the corresponding library from there.
143 std::string imgName;
144 if ( getEnv( name, imgName ) ) {
145 res = loadWithoutEnvironment( imgName, handle );
146 } else {
147 // build the dll name
148 std::string dllName = name;
149 // Add a possible "lib" prefix to the name on unix platforms. But only if
150 // it's not an absolute path name.
151 #if defined( __linux ) || defined( __APPLE__ )
152 if ( ( dllName.find( '/' ) == std::string::npos ) && ( dllName.compare( 0, 3, "lib" ) != 0 ) ) {
153 dllName = "lib" + dllName;
154 }
155 #endif // unix
156 // Now try loading the library with all possible suffixes supported by the
157 // platform.
158 for ( const char* suffix : SHLIB_SUFFIXES ) {
159 // Add the suffix if necessary.
160 std::string libName = dllName;
161 const size_t len = strlen( suffix );
162 if ( dllName.compare( dllName.length() - len, len, suffix ) != 0 ) { libName += suffix; }
163 // Try to load the library.
164 res = loadWithoutEnvironment( libName, handle );
165 // If the load succeeded, stop here.
166 if ( res == 1 ) { break; }
167 }
168 }
169 if ( res != 1 ) {
170 #if defined( __linux ) || defined( __APPLE__ )
171 errno = 0xAFFEDEAD;
172 #endif
173 // std::cout << "System::loadDynamicLib>" << getLastErrorString() << std::endl;
174 }
175 }
176 return res;
177 }
178
180 unsigned long System::unloadDynamicLib( ImageHandle handle ) {
181 #ifdef _WIN32
182 if ( !::FreeLibrary( (HINSTANCE)handle ) ) {
183 #elif defined( __linux ) || defined( __APPLE__ )
184 ::dlclose( handle );
185 if ( 0 ) {
186 #elif __hpux
187 // On HP we have to run finalization ourselves.....
188 Creator pFinalize = 0;
189 if ( getProcedureByName( handle, "_fini", &pFinalize ) ) { pFinalize(); }
190 HMODULE* mod = (HMODULE*)handle;
191 if ( 0 == ::shl_unload( mod->dsc.handle ) ) {
192 delete mod;
193 } else {
194 #else
195 if ( false ) {
196 #endif
197 return getLastError();
198 }
199 return 1;
200 }
201
203 unsigned long System::getProcedureByName( ImageHandle handle, const std::string& name, EntryPoint* pFunction ) {
204 #ifdef _WIN32
205 *pFunction = ( EntryPoint )::GetProcAddress( (HINSTANCE)handle, name.data() );
206 if ( 0 == *pFunction ) { return System::getLastError(); }
207 return 1;
208 #elif defined( __linux )
209 *pFunction = reinterpret_cast<EntryPoint>( ::dlsym( handle, name.c_str() ) );
210 if ( !*pFunction ) {
211 errno = 0xAFFEDEAD;
212 // std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
213 return 0;
214 }
215 return 1;
216 #elif defined( __APPLE__ )
217 *pFunction = ( EntryPoint )::dlsym( handle, name.c_str() );
218 if ( !( *pFunction ) ) {
219 // Try with an underscore :
220 std::string sname = "_" + name;
221 *pFunction = ( EntryPoint )::dlsym( handle, sname.c_str() );
222 }
223 if ( 0 == *pFunction ) {
224 errno = 0xAFFEDEAD;
225 std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
226 // std::cout << "System::getProcedureByName> failure" << std::endl;
227 return 0;
228 }
229 return 1;
230 #elif __hpux
231 HMODULE* mod = (HMODULE*)handle;
232 if ( 0 != mod ) {
233 long ll1 = name.length();
234 for ( int i = 0; i < mod->numSym; i++ ) {
235 long ll2 = strlen( mod->sym[i].name );
236 if ( 0 != ::strncmp( mod->sym[i].name, name.c_str(), ( ll1 > ll2 ) ? ll1 : ll2 ) == 0 ) {
237 *pFunction = (EntryPoint)mod->sym[i].value;
238 return 1;
239 }
240 }
241 }
242 return 0;
243 #endif
244 }
245
247 unsigned long System::getProcedureByName( ImageHandle handle, const std::string& name, Creator* pFunction ) {
248 return getProcedureByName( handle, name, (EntryPoint*)pFunction );
249 }
250
252 unsigned long System::getLastError() {
253 #ifdef _WIN32
254 return ::GetLastError();
255 #else
256 // convert errno (int) to unsigned long
257 return static_cast<unsigned long>( static_cast<unsigned int>( errno ) );
258 #endif
259 }
260
262 const std::string System::getLastErrorString() {
263 const std::string errString = getErrorString( getLastError() );
264 return errString;
265 }
266
268 const std::string System::getErrorString( unsigned long error ) {
269 std::string errString = "";
270 #ifdef _WIN32
271 LPVOID lpMessageBuffer;
272 ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error,
273 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // The user default language
274 (LPTSTR)&lpMessageBuffer, 0, NULL );
275 errString = (const char*)lpMessageBuffer;
276 // Free the buffer allocated by the system
277 ::LocalFree( lpMessageBuffer );
278 #else
279 char* cerrString( nullptr );
280 // Remember: for linux dl* routines must be handled differently!
281 if ( error == 0xAFFEDEAD ) {
282 cerrString = ::dlerror();
283 if ( !cerrString ) cerrString = ::strerror( error );
284 if ( !cerrString ) {
285 cerrString = (char*)"Unknown error. No information found in strerror()!";
286 } else {
287 errString = std::string( cerrString );
288 }
289 errno = 0;
290 } else {
291 cerrString = ::strerror( error );
292 errString = std::string( cerrString );
293 }
294 #endif
295 return errString;
296 }
297
298 const std::string System::typeinfoName( const std::type_info& tinfo ) { return typeinfoName( tinfo.name() ); }
299
300 const std::string System::typeinfoName( const char* class_name ) { return Platform::typeinfoName( class_name ); }
301
303 const std::string& System::hostName() {
304 static const std::string host = Platform::hostName();
305 return host;
306 }
307
309 const std::string& System::osName() {
310 static const std::string osname = Platform::osName();
311 return osname;
312 }
313
315 const std::string& System::osVersion() {
316 static const std::string osver = Platform::osVersion();
317 return osver;
318 }
319
321 const std::string& System::machineType() {
322 static const std::string mach = Platform::machineType();
323 return mach;
324 }
325
326 int System::instructionsetLevel() {
327 using namespace Gaudi;
328 return instrset_detect();
329 }
330
332 const std::string& System::accountName() {
333 static const std::string account = Platform::accountName();
334 return account;
335 }
336
338 long System::numCmdLineArgs() { return cmdLineArgs().size(); }
339
341 long System::argc() { return cmdLineArgs().size(); }
342
344 const std::vector<std::string> System::cmdLineArgs() {
345 static const std::vector<std::string> args = Platform::cmdLineArgs();
346 return args;
347 }
348
350 char** System::argv() {
351 auto helperFunc = []( const std::vector<std::string>& args ) -> std::vector<const char*> {
352 std::vector<const char*> result;
353 std::transform( args.begin(), args.end(), std::back_inserter( result ),
354 []( const std::string& s ) { return s.c_str(); } );
355 return result;
356 };
357 static const std::vector<const char*> args = helperFunc( cmdLineArgs() );
358 // We rely here on the fact that a vector's allocation table is contiguous
359 return (char**)&( args[0] );
360 }
361
362 #ifdef WIN32
363 // disable warning
364 // C4996: 'getenv': This function or variable may be unsafe.
365 # pragma warning( disable : 4996 )
366 #endif
367
369 std::string System::getEnv( const char* var ) {
370 char* env;
371 if ( ( env = getenv( var ) ) != nullptr ) {
372 return env;
373 } else {
374 return "UNKNOWN";
375 }
376 }
377
379 bool System::getEnv( const char* var, std::string& value ) {
380 char* env;
381 if ( ( env = getenv( var ) ) != nullptr ) {
382 value = env;
383 return true;
384 } else {
385 return false;
386 }
387 }
388
389 bool System::isEnvSet( const char* var ) { return getenv( var ) != nullptr; }
390
392 #if defined( __APPLE__ )
393 // Needed for _NSGetEnviron(void)
394 # include "crt_externs.h"
395 #endif
396 std::vector<std::string> System::getEnv() {
397 #if defined( _WIN32 )
398 # define environ _environ
399 #elif defined( __APPLE__ )
400 static char** environ = *_NSGetEnviron();
401 #endif
402 std::vector<std::string> vars;
403 for ( int i = 0; environ[i] != nullptr; ++i ) { vars.push_back( environ[i] ); }
404 return vars;
405 }
406
407 // -----------------------------------------------------------------------------
408 // backtrace utilities
409 // -----------------------------------------------------------------------------
410 #ifdef __linux
411 # include <execinfo.h>
412 #endif
413
414 int System::backTrace( [[maybe_unused]] void** addresses, [[maybe_unused]] const int depth ) {
415
416 #ifdef __linux
417
418 int count = backtrace( addresses, depth );
419 return count > 0 ? count : 0;
420
421 #else // windows and osx parts not implemented
422 return 0;
423 #endif
424 }
425
426 bool System::backTrace( std::string& btrace, const int depth, const int offset ) {
427 try {
428 // Always hide the first two levels of the stack trace (that's us)
429 const int totalOffset = offset + 2;
430 const int totalDepth = depth + totalOffset;
431
432 std::string fnc, lib;
433
434 std::vector<void*> addresses( totalDepth, nullptr );
435 int count = System::backTrace( addresses.data(), totalDepth );
436 for ( int i = totalOffset; i < count; ++i ) {
437 void* addr = nullptr;
438
439 if ( System::getStackLevel( addresses[i], addr, fnc, lib ) ) {
440 std::ostringstream ost;
441 ost << "#" << std::setw( 3 ) << std::setiosflags( std::ios::left ) << i - totalOffset + 1;
442 ost << std::hex << addr << std::dec << " " << fnc << " [" << lib << "]" << std::endl;
443 btrace += ost.str();
444 }
445 }
446 return true;
447 } catch ( const std::bad_alloc& e ) { return false; }
448 }
449
450 bool System::getStackLevel( [[maybe_unused]] void* addresses, [[maybe_unused]] void*& addr,
451 [[maybe_unused]] std::string& fnc, [[maybe_unused]] std::string& lib ) {
452
453 #ifdef __linux
454
455 Dl_info info;
456
457 if ( dladdr( addresses, &info ) && info.dli_fname && info.dli_fname[0] != '\0' ) {
458 const char* symbol = info.dli_sname && info.dli_sname[0] != '\0' ? info.dli_sname : nullptr;
459
460 lib = info.dli_fname;
461 addr = info.dli_saddr;
462
463 if ( symbol ) {
464 int stat = -1;
465 auto dmg =
466 std::unique_ptr<char, decltype( free )*>( abi::__cxa_demangle( symbol, nullptr, nullptr, &stat ), std::free );
467 fnc = ( stat == 0 ) ? dmg.get() : symbol;
468 } else {
469 fnc = "local";
470 }
471 return true;
472 } else {
473 return false;
474 }
475
476 #else // not implemented for windows and osx
477 return false;
478 #endif
479 }
480
482 int System::setEnv( const std::string& name, const std::string& value, int overwrite ) {
483 #ifndef WIN32
484 // UNIX version
485 return value.empty() ?
486 // remove if set to nothing (and return success)
487 ::unsetenv( name.c_str() ),
488 0 :
489 // set the value
490 ::setenv( name.c_str(), value.c_str(), overwrite );
491 #else
492 // Windows version
493 if ( value.empty() ) {
494 // equivalent to unsetenv
495 return ::_putenv( ( name + "=" ).c_str() );
496 } else {
497 if ( !getenv( name.c_str() ) || overwrite ) {
498 // set if not yet present or overwrite is set (force)
499 return ::_putenv( ( name + "=" + value ).c_str() );
500 }
501 }
502 return 0; // if we get here, we are trying to set a variable already set, but
503 // not to overwrite.
504 // It is considered a success on Linux (man P setenv)
505 #endif
506 }
System::getEnv
GAUDI_API std::string getEnv(const char *var)
get a particular environment variable (returning "UNKNOWN" if not set)
Definition: System.cpp:369
System.h
System::argc
GAUDI_API long argc()
Number of arguments passed to the commandline (==numCmdLineArgs()); just to match argv call....
Definition: System.cpp:341
System::argv
GAUDI_API char ** argv()
char** command line arguments including executable name as arg[0]; You may not modify them!
Definition: System.cpp:350
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:268
System::setEnv
GAUDI_API int setEnv(const std::string &name, const std::string &value, int overwrite=1)
Set an environment variables.
Definition: System.cpp:482
System::getLastError
GAUDI_API unsigned long getLastError()
Get last system known error.
Definition: System.cpp:252
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:203
GaudiPython.HistoUtils.path
path
Definition: HistoUtils.py:932
gaudiComponentHelp.name
name
Definition: gaudiComponentHelp.py:41
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:298
SystemMacOS.h
System::instructionsetLevel
GAUDI_API int instructionsetLevel()
Instruction Set "Level".
Definition: System.cpp:326
compareOutputFiles.sname
string sname
Definition: compareOutputFiles.py:471
Gaudi.CommonGaudiConfigurables.mod
mod
Definition: CommonGaudiConfigurables.py:22
System::accountName
GAUDI_API const std::string & accountName()
User login name.
Definition: System.cpp:332
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:30
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:338
System::exeName
GAUDI_API const std::string & exeName()
Name of the executable file running.
Definition: ModuleInfo.cpp:193
instrset_detect.cpp
std::vector::push_back
T push_back(T... args)
std::vector::data
T data(T... args)
gaudirun.args
args
Definition: gaudirun.py:307
std::strlen
T strlen(T... args)
std::ostringstream
STL class.
System::osName
GAUDI_API const std::string & osName()
OS name.
Definition: System.cpp:309
instrset_detect
int instrset_detect(void)
Definition: instrset_detect.cpp:98
std::ostringstream::str
T str(T... args)
System::unloadDynamicLib
GAUDI_API unsigned long unloadDynamicLib(ImageHandle handle)
unload dynamic link library
Definition: System.cpp:180
System::isEnvSet
GAUDI_API bool isEnvSet(const char *var)
Check if an environment variable is set or not.
Definition: System.cpp:389
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:303
System::Creator
void *(* Creator)()
Definition of the "generic" DLL entry point function.
Definition: System.h:37
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:316
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:344
System::osVersion
GAUDI_API const std::string & osVersion()
OS version.
Definition: System.cpp:315
std::transform
T transform(T... args)
System::getLastErrorString
GAUDI_API const std::string getLastErrorString()
Get last system error as string.
Definition: System.cpp:262
System::machineType
GAUDI_API const std::string & machineType()
Machine type.
Definition: System.cpp:321
SystemWin32.h
std::cout
SystemLinux.h
Gaudi
Header file for std:chrono::duration-based Counters.
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:135
System::EntryPoint
unsigned long(* EntryPoint)(const unsigned long iid, void **ppvObject)
Definition of the "generic" DLL entry point function.
Definition: System.h:35