The Gaudi Framework  master (ff829712)
Loading...
Searching...
No Matches
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>
50struct HMODULE {
51 shl_descriptor dsc;
52 long numSym;
53 shl_symbol* sym;
54};
55#endif // HPUX or not...
56
57#ifdef __APPLE__
58static const std::array<const char*, 2> SHLIB_SUFFIXES = { ".dylib", ".so" };
59#else
60static const std::array<const char*, 1> SHLIB_SUFFIXES = { ".so" };
61#endif // __APPLE__
62
63static 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
89static 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
115unsigned 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
160unsigned 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
181unsigned 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
223unsigned long System::getProcedureByName( ImageHandle handle, const std::string& name, Creator* pFunction ) {
224 return getProcedureByName( handle, name, (EntryPoint*)pFunction );
225}
226
228unsigned long System::getLastError() {
229 // convert errno (int) to unsigned long
230 return static_cast<unsigned long>( static_cast<unsigned int>( errno ) );
231}
232
234const std::string System::getLastErrorString() {
235 const std::string errString = getErrorString( getLastError() );
236 return errString;
237}
238
240const 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
260const std::string System::typeinfoName( const std::type_info& tinfo ) { return typeinfoName( tinfo.name() ); }
261
262const std::string System::typeinfoName( const char* class_name ) { return Platform::typeinfoName( class_name ); }
263
265const std::string& System::hostName() {
266 static const std::string host = Platform::hostName();
267 return host;
268}
269
271const std::string& System::osName() {
272 static const std::string osname = Platform::osName();
273 return osname;
274}
275
277const std::string& System::osVersion() {
278 static const std::string osver = Platform::osVersion();
279 return osver;
280}
281
283const 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
298const std::string& System::accountName() {
299 static const std::string account = Platform::accountName();
300 return account;
301}
302
304long System::numCmdLineArgs() { return cmdLineArgs().size(); }
305
307long System::argc() { return cmdLineArgs().size(); }
308
310const std::vector<std::string> System::cmdLineArgs() {
311 static const std::vector<std::string> args = Platform::cmdLineArgs();
312 return args;
313}
314
316char** 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
329std::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
339bool 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
349bool 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
356std::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
372int 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
384bool 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
408bool 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
440int 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}
GAUDI_API std::string getEnv(const char *var)
get a particular environment variable (returning "UNKNOWN" if not set)
Definition System.cpp:329
int instrset_detect(void)
GAUDI_API std::string path(const AIDA::IBaseHistogram *aida)
get the path in THS for AIDA histogram
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1
GAUDI_API bool getStackLevel(void *addresses, void *&addr, std::string &fnc, std::string &lib)
Definition System.cpp:408
GAUDI_API const std::string & osName()
OS name.
Definition System.cpp:271
GAUDI_API int backTrace(void **addresses, const int depth)
Definition System.cpp:372
void *(* Creator)()
Definition of the "generic" DLL entry point function.
Definition System.h:43
GAUDI_API bool isEnvSet(const char *var)
Check if an environment variable is set or not.
Definition System.cpp:349
unsigned long(* EntryPoint)(const unsigned long iid, void **ppvObject)
Definition of the "generic" DLL entry point function.
Definition System.h:41
GAUDI_API const std::string & machineType()
Machine type.
Definition System.cpp:283
GAUDI_API unsigned long loadDynamicLib(const std::string &name, ImageHandle *handle)
Load dynamic link library.
Definition System.cpp:115
GAUDI_API long numCmdLineArgs()
Number of arguments passed to the commandline.
Definition System.cpp:304
GAUDI_API const std::string getLastErrorString()
Get last system error as string.
Definition System.cpp:234
GAUDI_API unsigned long unloadDynamicLib(ImageHandle handle)
unload dynamic link library
Definition System.cpp:160
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
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition System.cpp:260
void * ImageHandle
Definition of an image handle.
Definition ModuleInfo.h:25
GAUDI_API std::vector< std::string > getEnv()
get all environment variables
Definition System.cpp:356
GAUDI_API const std::string & hostName()
Host name.
Definition System.cpp:265
GAUDI_API const std::string & accountName()
User login name.
Definition System.cpp:298
GAUDI_API unsigned long getLastError()
Get last system known error.
Definition System.cpp:228
GAUDI_API long argc()
Number of arguments passed to the commandline (==numCmdLineArgs()); just to match argv call....
Definition System.cpp:307
GAUDI_API const std::string getErrorString(unsigned long error)
Retrieve error code as string for a given error.
Definition System.cpp:240
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
GAUDI_API int setEnv(const std::string &name, const std::string &value, int overwrite=1)
Set an environment variables.
Definition System.cpp:440
GAUDI_API char ** argv()
char** command line arguments including executable name as arg[0]; You may not modify them!
Definition System.cpp:316
GAUDI_API const std::string & osVersion()
OS version.
Definition System.cpp:277
GAUDI_API int instructionsetLevel()
Instruction Set "Level".
Definition System.cpp:288