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