Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v30r0 (c919700c)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 
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 
342 {
343  static const std::string host = Platform::hostName();
344  return host;
345 }
346 
349 {
350  static const std::string osname = Platform::osName();
351  return osname;
352 }
353 
356 {
357  static const std::string osver = Platform::osVersion();
358  return osver;
359 }
360 
363 {
364  static const std::string mach = Platform::machineType();
365  return mach;
366 }
367 
369 {
370  using namespace Gaudi;
371  return instrset_detect();
372 }
373 
376 {
377  static const std::string account = Platform::accountName();
378  return account;
379 }
380 
383 
385 long System::argc() { return cmdLineArgs().size(); }
386 
389 {
391  return args;
392 }
393 
395 char** System::argv()
396 {
397  auto helperFunc = []( const std::vector<std::string>& args ) -> std::vector<const char*> {
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
445 {
446 #if defined( _WIN32 )
447 #define environ _environ
448 #elif defined( __APPLE__ )
449  static char** environ = *_NSGetEnviron();
450 #endif
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 }
GAUDI_API std::string getEnv(const char *var)
get a particular environment variable (returning "UNKNOWN" if not set)
Definition: System.cpp:415
GAUDI_API long argc()
Number of arguments passed to the commandline (==numCmdLineArgs()); just to match argv call...
Definition: System.cpp:385
GAUDI_API char ** argv()
char** command line arguments including executable name as arg[0]; You may not modify them! ...
Definition: System.cpp:395
#define __attribute__(x)
Definition: System.cpp:89
T empty(T...args)
GAUDI_API const std::string getErrorString(unsigned long error)
Retrieve error code as string for a given error.
Definition: System.cpp:305
GAUDI_API int setEnv(const std::string &name, const std::string &value, int overwrite=1)
Set an environment variables.
Definition: System.cpp:538
GAUDI_API unsigned long getLastError()
Get last system known error.
Definition: System.cpp:287
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
GAUDI_API bool getStackLevel(void *addresses, void *&addr, std::string &fnc, std::string &lib)
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:336
GAUDI_API int instructionsetLevel()
Instruction Set "Level".
Definition: System.cpp:368
GAUDI_API const std::string & accountName()
User login name.
Definition: System.cpp:375
T endl(T...args)
T free(T...args)
T setiosflags(T...args)
void * ImageHandle
Definition of an image handle.
Definition: ModuleInfo.h:31
GAUDI_API int backTrace(void **addresses, const int depth)
T setw(T...args)
STL class.
GAUDI_API long numCmdLineArgs()
Number of arguments passed to the commandline.
Definition: System.cpp:382
GAUDI_API const std::string & exeName()
Name of the executable file running.
Definition: ModuleInfo.cpp:210
T push_back(T...args)
T data(T...args)
GAUDI_API const std::string & osName()
OS name.
Definition: System.cpp:348
int instrset_detect(void)
GAUDI_API unsigned long unloadDynamicLib(ImageHandle handle)
unload dynamic link library
Definition: System.cpp:204
GAUDI_API bool isEnvSet(const char *var)
Check if an environment variable is set or not.
Definition: System.cpp:437
T get(T...args)
T find(T...args)
T length(T...args)
GAUDI_API const std::string & hostName()
Host name.
Definition: System.cpp:341
void *(* Creator)()
Definition of the "generic" DLL entry point function.
Definition: System.h:38
T name(T...args)
STL class.
T back_inserter(T...args)
STL class.
T c_str(T...args)
string s
Definition: gaudirun.py:253
STL class.
T hex(T...args)
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
GAUDI_API const std::string & osVersion()
OS version.
Definition: System.cpp:355
T transform(T...args)
GAUDI_API const std::string getLastErrorString()
Get last system error as string.
Definition: System.cpp:298
GAUDI_API const std::string & machineType()
Machine type.
Definition: System.cpp:362
Helper functions to set/get the application return code.
Definition: __init__.py:1
T compare(T...args)
GAUDI_API unsigned long loadDynamicLib(const std::string &name, ImageHandle *handle)
Load dynamic link library.
Definition: System.cpp:154
unsigned long(* EntryPoint)(const unsigned long iid, void **ppvObject)
Definition of the "generic" DLL entry point function.
Definition: System.h:36