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