Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  master (d98a2936)
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 * (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
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 #include <GaudiKernel/System.h>
12 #include <algorithm>
13 #include <array>
14 #include <cstdlib>
15 #include <cstring>
16 #include <ctime>
17 #include <iomanip>
18 #include <iostream>
19 #include <memory>
20 #include <regex>
21 #include <sstream>
22 #include <typeinfo>
23 
24 // Platform specific include(s):
25 #ifdef __linux__
26 # include "Platform/SystemLinux.h"
27 #elif defined( __APPLE__ )
28 # include "Platform/SystemMacOS.h"
29 #endif
30 
31 #ifdef __x86_64
32 # define VCL_NAMESPACE Gaudi
33 # include <instrset_detect.cpp>
34 # undef VCL_NAMESPACE
35 #endif
36 
37 #include <cstdio>
38 #include <cxxabi.h>
39 #include <errno.h>
40 #include <libgen.h>
41 #include <string.h>
42 #include <sys/times.h>
43 #include <unistd.h>
44 #if defined( __linux ) || defined( __APPLE__ )
45 # include <dlfcn.h>
46 # include <sys/utsname.h>
47 # include <unistd.h>
48 #elif __hpux
49 # include <dl.h>
50 struct HMODULE {
51  shl_descriptor dsc;
52  long numSym;
53  shl_symbol* sym;
54 };
55 #endif // HPUX or not...
56 
57 #ifdef __APPLE__
58 static const std::array<const char*, 2> SHLIB_SUFFIXES = { ".dylib", ".so" };
59 #else
60 static const std::array<const char*, 1> SHLIB_SUFFIXES = { ".so" };
61 #endif // __APPLE__
62 
63 static unsigned long doLoad( const std::string& name, System::ImageHandle* handle ) {
64  const char* path = name.c_str();
65 #if defined( __linux )
66  void* mh = ::dlopen( name.length() == 0 ? nullptr : path, RTLD_LAZY | RTLD_GLOBAL );
67  *handle = mh;
68 #elif defined( __APPLE__ )
69  void* mh = ::dlopen( name.length() == 0 ? nullptr : path, RTLD_LAZY | RTLD_GLOBAL );
70  *handle = mh;
71 #elif __hpux
72  shl_t mh = ::shl_load( name.length() == 0 ? 0 : path, BIND_IMMEDIATE | BIND_VERBOSE, 0 );
73  HMODULE* mod = new HMODULE;
74  if ( 0 != mh ) {
75  if ( 0 != ::shl_gethandle_r( mh, &mod->dsc ) ) {
76  std::cout << "System::loadDynamicLib>" << ::strerror( getLastError() ) << std::endl;
77  } else {
78  typedef void* ( *___all )();
79  ___all _alloc = (___all)malloc;
80  mod->numSym = ::shl_getsymbols( mod->dsc.handle, TYPE_PROCEDURE, EXPORT_SYMBOLS, malloc, &mod->sym );
81  *handle = mod;
82  }
83  }
84 #endif
85  if ( !*handle ) { return System::getLastError(); }
86  return 1;
87 }
88 
89 static unsigned long loadWithoutEnvironment( const std::string& name, System::ImageHandle* handle ) {
90 
91  // If the name is empty, don't do anything complicated.
92  if ( name.length() == 0 ) { return doLoad( name, handle ); }
93 
94  // Check if the specified name has a shared library suffix already. If it
95  // does, don't bother the name any more.
96  std::string dllName = name;
97  bool hasShlibSuffix = false;
98  for ( const char* suffix : SHLIB_SUFFIXES ) {
99  const size_t len = strlen( suffix );
100  if ( dllName.compare( dllName.length() - len, len, suffix ) == 0 ) {
101  hasShlibSuffix = true;
102  break;
103  }
104  }
105 
106  // If it doesn't have a shared library suffix on it, add the "default" shared
107  // library suffix to the name.
108  if ( !hasShlibSuffix ) { dllName += SHLIB_SUFFIXES[0]; }
109 
110  // Load the library.
111  return doLoad( dllName, handle );
112 }
113 
115 unsigned long System::loadDynamicLib( const std::string& name, ImageHandle* handle ) {
116  unsigned long res = 0;
117  // if name is empty, just load it
118  if ( name.length() == 0 ) {
119  res = loadWithoutEnvironment( name, handle );
120  } else {
121  // If the name is a logical name (environment variable), the try
122  // to load the corresponding library from there.
123  std::string imgName;
124  if ( getEnv( name, imgName ) ) {
125  res = loadWithoutEnvironment( imgName, handle );
126  } else {
127  // build the dll name
128  std::string dllName = name;
129 // Add a possible "lib" prefix to the name on unix platforms. But only if
130 // it's not an absolute path name.
131 #if defined( __linux ) || defined( __APPLE__ )
132  if ( ( dllName.find( '/' ) == std::string::npos ) && ( dllName.compare( 0, 3, "lib" ) != 0 ) ) {
133  dllName = "lib" + dllName;
134  }
135 #endif // unix
136  // Now try loading the library with all possible suffixes supported by the
137  // platform.
138  for ( const char* suffix : SHLIB_SUFFIXES ) {
139  // Add the suffix if necessary.
140  std::string libName = dllName;
141  const size_t len = strlen( suffix );
142  if ( dllName.compare( dllName.length() - len, len, suffix ) != 0 ) { libName += suffix; }
143  // Try to load the library.
144  res = loadWithoutEnvironment( libName, handle );
145  // If the load succeeded, stop here.
146  if ( res == 1 ) { break; }
147  }
148  }
149  if ( res != 1 ) {
150 #if defined( __linux ) || defined( __APPLE__ )
151  errno = 0xAFFEDEAD;
152 #endif
153  // std::cout << "System::loadDynamicLib>" << getLastErrorString() << std::endl;
154  }
155  }
156  return res;
157 }
158 
160 unsigned long System::unloadDynamicLib( ImageHandle handle ) {
161 #if defined( __linux ) || defined( __APPLE__ )
162  ::dlclose( handle );
163  if ( 0 ) {
164 #elif __hpux
165  // On HP we have to run finalization ourselves.....
166  Creator pFinalize = 0;
167  if ( getProcedureByName( handle, "_fini", &pFinalize ) ) { pFinalize(); }
168  HMODULE* mod = (HMODULE*)handle;
169  if ( 0 == ::shl_unload( mod->dsc.handle ) ) {
170  delete mod;
171  } else {
172 #else
173  if ( false ) {
174 #endif
175  return getLastError();
176  }
177  return 1;
178 }
179 
181 unsigned long System::getProcedureByName( ImageHandle handle, const std::string& name, EntryPoint* pFunction ) {
182 #if defined( __linux )
183  *pFunction = reinterpret_cast<EntryPoint>( ::dlsym( handle, name.c_str() ) );
184  if ( !*pFunction ) {
185  errno = 0xAFFEDEAD;
186  // std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
187  return 0;
188  }
189  return 1;
190 #elif defined( __APPLE__ )
191  *pFunction = ( EntryPoint )::dlsym( handle, name.c_str() );
192  if ( !( *pFunction ) ) {
193  // Try with an underscore :
194  std::string sname = "_" + name;
195  *pFunction = ( EntryPoint )::dlsym( handle, sname.c_str() );
196  }
197  if ( 0 == *pFunction ) {
198  errno = 0xAFFEDEAD;
199  std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
200  // std::cout << "System::getProcedureByName> failure" << std::endl;
201  return 0;
202  }
203  return 1;
204 #elif __hpux
205  HMODULE* mod = (HMODULE*)handle;
206  if ( 0 != mod ) {
207  long ll1 = name.length();
208  for ( int i = 0; i < mod->numSym; i++ ) {
209  long ll2 = strlen( mod->sym[i].name );
210  if ( 0 != ::strncmp( mod->sym[i].name, name.c_str(), ( ll1 > ll2 ) ? ll1 : ll2 ) == 0 ) {
211  *pFunction = (EntryPoint)mod->sym[i].value;
212  return 1;
213  }
214  }
215  }
216  return 0;
217 #else
218  return 0;
219 #endif
220 }
221 
223 unsigned long System::getProcedureByName( ImageHandle handle, const std::string& name, Creator* pFunction ) {
224  return getProcedureByName( handle, name, (EntryPoint*)pFunction );
225 }
226 
228 unsigned long System::getLastError() {
229  // convert errno (int) to unsigned long
230  return static_cast<unsigned long>( static_cast<unsigned int>( errno ) );
231 }
232 
234 const std::string System::getLastErrorString() {
235  const std::string errString = getErrorString( getLastError() );
236  return errString;
237 }
238 
240 const std::string System::getErrorString( unsigned long error ) {
241  std::string errString = "";
242  char* cerrString( nullptr );
243  // Remember: for linux dl* routines must be handled differently!
244  if ( error == 0xAFFEDEAD ) {
245  cerrString = ::dlerror();
246  if ( !cerrString ) cerrString = ::strerror( error );
247  if ( !cerrString ) {
248  cerrString = (char*)"Unknown error. No information found in strerror()!";
249  } else {
250  errString = std::string( cerrString );
251  }
252  errno = 0;
253  } else {
254  cerrString = ::strerror( error );
255  errString = std::string( cerrString );
256  }
257  return errString;
258 }
259 
260 const std::string System::typeinfoName( const std::type_info& tinfo ) { return typeinfoName( tinfo.name() ); }
261 
262 const std::string System::typeinfoName( const char* class_name ) { return Platform::typeinfoName( class_name ); }
263 
265 const std::string& System::hostName() {
266  static const std::string host = Platform::hostName();
267  return host;
268 }
269 
271 const std::string& System::osName() {
272  static const std::string osname = Platform::osName();
273  return osname;
274 }
275 
277 const std::string& System::osVersion() {
278  static const std::string osver = Platform::osVersion();
279  return osver;
280 }
281 
283 const std::string& System::machineType() {
284  static const std::string mach = Platform::machineType();
285  return mach;
286 }
287 
289 #ifdef __x86_64
290  using namespace Gaudi;
291  return instrset_detect();
292 #else
293  return -1;
294 #endif
295 }
296 
298 const std::string& System::accountName() {
299  static const std::string account = Platform::accountName();
300  return account;
301 }
302 
304 long System::numCmdLineArgs() { return cmdLineArgs().size(); }
305 
307 long System::argc() { return cmdLineArgs().size(); }
308 
310 const std::vector<std::string> System::cmdLineArgs() {
311  static const std::vector<std::string> args = Platform::cmdLineArgs();
312  return args;
313 }
314 
316 char** System::argv() {
317  auto helperFunc = []( const std::vector<std::string>& args ) -> std::vector<const char*> {
318  std::vector<const char*> result;
319  std::transform( args.begin(), args.end(), std::back_inserter( result ),
320  []( const std::string& s ) { return s.c_str(); } );
321  return result;
322  };
323  static const std::vector<const char*> args = helperFunc( cmdLineArgs() );
324  // We rely here on the fact that a vector's allocation table is contiguous
325  return (char**)&( args[0] );
326 }
327 
329 std::string System::getEnv( const char* var ) {
330  char* env;
331  if ( ( env = getenv( var ) ) != nullptr ) {
332  return env;
333  } else {
334  return "UNKNOWN";
335  }
336 }
337 
339 bool System::getEnv( const char* var, std::string& value ) {
340  char* env;
341  if ( ( env = getenv( var ) ) != nullptr ) {
342  value = env;
343  return true;
344  } else {
345  return false;
346  }
347 }
348 
349 bool System::isEnvSet( const char* var ) { return getenv( var ) != nullptr; }
350 
352 #if defined( __APPLE__ )
353 // Needed for _NSGetEnviron(void)
354 # include <crt_externs.h>
355 #endif
356 std::vector<std::string> System::getEnv() {
357 #if defined( __APPLE__ )
358  static char** environ = *_NSGetEnviron();
359 #endif
360  std::vector<std::string> vars;
361  for ( int i = 0; environ[i] != nullptr; ++i ) { vars.push_back( environ[i] ); }
362  return vars;
363 }
364 
365 // -----------------------------------------------------------------------------
366 // backtrace utilities
367 // -----------------------------------------------------------------------------
368 #ifdef __linux
369 # include <execinfo.h>
370 #endif
371 
372 int System::backTrace( [[maybe_unused]] void** addresses, [[maybe_unused]] const int depth ) {
373 
374 #ifdef __linux
375 
376  int count = backtrace( addresses, depth );
377  return count > 0 ? count : 0;
378 
379 #else // osx parts not implemented
380  return 0;
381 #endif
382 }
383 
384 bool System::backTrace( std::string& btrace, const int depth, const int offset ) {
385  try {
386  // Always hide the first two levels of the stack trace (that's us)
387  const size_t totalOffset = offset + 2;
388  const size_t totalDepth = depth + totalOffset;
389 
390  std::string fnc, lib;
391 
392  std::vector<void*> addresses( totalDepth, nullptr );
393  const size_t count = System::backTrace( addresses.data(), totalDepth );
394  for ( size_t i = totalOffset; i < count; ++i ) {
395  void* addr = nullptr;
396 
397  if ( System::getStackLevel( addresses[i], addr, fnc, lib ) ) {
398  std::ostringstream ost;
399  ost << "#" << std::setw( 3 ) << std::setiosflags( std::ios::left ) << i - totalOffset + 1;
400  ost << std::hex << addr << std::dec << " " << fnc << " [" << lib << "]" << std::endl;
401  btrace += ost.str();
402  }
403  }
404  return true;
405  } catch ( const std::bad_alloc& e ) { return false; }
406 }
407 
408 bool System::getStackLevel( [[maybe_unused]] void* addresses, [[maybe_unused]] void*& addr,
409  [[maybe_unused]] std::string& fnc, [[maybe_unused]] std::string& lib ) {
410 
411 #ifdef __linux
412 
413  Dl_info info;
414 
415  if ( dladdr( addresses, &info ) && info.dli_fname && info.dli_fname[0] != '\0' ) {
416  const char* symbol = info.dli_sname && info.dli_sname[0] != '\0' ? info.dli_sname : nullptr;
417 
418  lib = info.dli_fname;
419  addr = info.dli_saddr;
420 
421  if ( symbol ) {
422  int stat = -1;
423  auto dmg =
424  std::unique_ptr<char, decltype( free )*>( abi::__cxa_demangle( symbol, nullptr, nullptr, &stat ), std::free );
425  fnc = ( stat == 0 ) ? dmg.get() : symbol;
426  } else {
427  fnc = "local";
428  }
429  return true;
430  } else {
431  return false;
432  }
433 
434 #else // not implemented for osx
435  return false;
436 #endif
437 }
438 
440 int System::setEnv( const std::string& name, const std::string& value, int overwrite ) {
441  return value.empty() ?
442  // remove if set to nothing (and return success)
443  ::unsetenv( name.c_str() ),
444  0 :
445  // set the value
446  ::setenv( name.c_str(), value.c_str(), overwrite );
447 }
System::getErrorString
GAUDI_API const std::string getErrorString(unsigned long error)
Retrieve error code as string for a given error.
Definition: System.cpp:240
instrset_detect.cpp
MSG::hex
MsgStream & hex(MsgStream &log)
Definition: MsgStream.h:258
System::loadDynamicLib
GAUDI_API unsigned long loadDynamicLib(const std::string &name, ImageHandle *handle)
Load dynamic link library.
Definition: System.cpp:115
compareOutputFiles.sname
sname
Definition: compareOutputFiles.py:483
System::argc
GAUDI_API long argc()
Number of arguments passed to the commandline (==numCmdLineArgs()); just to match argv call....
Definition: System.cpp:307
AtlasMCRecoFullPrecedenceDump.path
path
Definition: AtlasMCRecoFullPrecedenceDump.py:49
System::getLastError
GAUDI_API unsigned long getLastError()
Get last system known error.
Definition: System.cpp:228
System::EntryPoint
unsigned long(* EntryPoint)(const unsigned long iid, void **ppvObject)
Definition of the "generic" DLL entry point function.
Definition: System.h:41
System.h
gaudirun.s
string s
Definition: gaudirun.py:346
System::getEnv
GAUDI_API std::string getEnv(const char *var)
get a particular environment variable (returning "UNKNOWN" if not set)
Definition: System.cpp:329
System::setEnv
GAUDI_API int setEnv(const std::string &name, const std::string &value, int overwrite=1)
Set an environment variables.
Definition: System.cpp:440
System::instructionsetLevel
GAUDI_API int instructionsetLevel()
Instruction Set "Level".
Definition: System.cpp:288
System::ImageHandle
void * ImageHandle
Definition of an image handle.
Definition: ModuleInfo.h:25
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:181
System::typeinfoName
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:260
System::getStackLevel
GAUDI_API bool getStackLevel(void *addresses, void *&addr, std::string &fnc, std::string &lib)
System::backTrace
GAUDI_API int backTrace(void **addresses, const int depth)
System::osName
GAUDI_API const std::string & osName()
OS name.
Definition: System.cpp:271
System::accountName
GAUDI_API const std::string & accountName()
User login name.
Definition: System.cpp:298
Gaudi.CommonGaudiConfigurables.mod
mod
Definition: CommonGaudiConfigurables.py:39
SystemLinux.h
SystemMacOS.h
MSG::dec
MsgStream & dec(MsgStream &log)
Definition: MsgStream.h:254
System::numCmdLineArgs
GAUDI_API long numCmdLineArgs()
Number of arguments passed to the commandline.
Definition: System.cpp:304
instrset_detect
int instrset_detect(void)
Definition: instrset_detect.cpp:63
System::isEnvSet
GAUDI_API bool isEnvSet(const char *var)
Check if an environment variable is set or not.
Definition: System.cpp:349
Gaudi
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition: __init__.py:1
System::Creator
void *(* Creator)()
Definition of the "generic" DLL entry point function.
Definition: System.h:43
System::unloadDynamicLib
GAUDI_API unsigned long unloadDynamicLib(ImageHandle handle)
unload dynamic link library
Definition: System.cpp:160
ConditionsStallTest.name
name
Definition: ConditionsStallTest.py:77
gaudirun.args
args
Definition: gaudirun.py:336
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:310
System::machineType
GAUDI_API const std::string & machineType()
Machine type.
Definition: System.cpp:283
System::hostName
GAUDI_API const std::string & hostName()
Host name.
Definition: System.cpp:265
System::getLastErrorString
GAUDI_API const std::string getLastErrorString()
Get last system error as string.
Definition: System.cpp:234
System::osVersion
GAUDI_API const std::string & osVersion()
OS version.
Definition: System.cpp:277
System::argv
GAUDI_API char ** argv()
char** command line arguments including executable name as arg[0]; You may not modify them!
Definition: System.cpp:316