| # Gaudi Framework, version v25r0 |

Home |  | Generated: Mon Feb 17 2014

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
System.cpp
Go to the documentation of this file.
1 // $Id: System.cpp,v 1.45 2008/10/27 21:30:32 marcocle Exp $
2 //====================================================================
3 // System.cpp
4 //--------------------------------------------------------------------
5 //
6 // Package : System (The LHCb System service)
7 //
8 // Description: Implementation of Systems internals
9 //
10 // Author : M.Frank
11 // Created : 13/1/99
12 // Changes :
13 //====================================================================
14 #define SYSTEM_SYSTEM_CPP
15 #include <ctime>
16 #include <cstring>
17 #include <cstdlib>
18 #include <iomanip>
19 #include <iostream>
20 #include <sstream>
21 #include <typeinfo>
22
23 #include "GaudiKernel/System.h"
24
25 #ifdef _WIN32
26 #define strcasecmp _stricmp
27 #define strncasecmp _strnicmp
28 #define getpid _getpid
29 #define NOMSG
30 #define NOGDI
31 #include "process.h"
32 #include "windows.h"
33 #undef NOMSG
34 #undef NOGDI
35 static const char* SHLIB_SUFFIX = ".dll";
36 #else // UNIX...: first the EGCS stuff, then the OS dependent includes
37 static const char* SHLIB_SUFFIX = ".so";
38 #include <errno.h>
39 #include <string.h>
40 #include "sys/times.h"
41 #include "unistd.h"
42 #include "libgen.h"
43 #include <cstdio>
44 #include <cxxabi.h>
45 #if defined(__linux) || defined(__APPLE__)
46 #include "dlfcn.h"
47 #include <sys/utsname.h>
48 #include <unistd.h>
49 #elif __hpux
50 #include "dl.h"
51 struct HMODULE {
52 shl_descriptor dsc;
53 long numSym;
54 shl_symbol* sym;
55 };
56 #endif
57
58 #endif
59
60 // Note: __attribute__ is a GCC keyword available since GCC 3.4
61 #ifdef __GNUC__
62 # if __GNUC__ < 3 || \
63 (__GNUC__ == 3 && (__GNUC_MINOR__ < 4 ))
64 // GCC < 3.4
65 # define __attribute__(x)
66 # endif
67 #else
68 // non-GCC
69 # define __attribute__(x)
70 #endif
71
72 static std::vector<std::string> s_argvStrings;
73 static std::vector<const char*> s_argvChars;
74
75 static unsigned long doLoad(const std::string& name, System::ImageHandle* handle) {
76 #ifdef _WIN32
77 void* mh = ::LoadLibrary( name.length() == 0 ? System::exeName().c_str() : name.c_str());
78 *handle = mh;
79 #else
80 const char* path = name.c_str();
81 #if defined(__linux) || defined(__APPLE__)
82 void *mh = ::dlopen(name.length() == 0 ? 0 : path, RTLD_LAZY | RTLD_GLOBAL);
83 *handle = mh;
84 #elif __hpux
85 shl_t mh = ::shl_load(name.length() == 0 ? 0 : path, BIND_IMMEDIATE | BIND_VERBOSE, 0);
86 HMODULE* mod = new HMODULE;
87 if ( 0 != mh ) {
88 if ( 0 != ::shl_gethandle_r(mh, &mod->dsc) ) {
89 std::cout << "System::loadDynamicLib>" << ::strerror(getLastError()) << std::endl;
90 }
91 else {
92 typedef void* (*___all)();
93 ___all _alloc = (___all)malloc;
94 mod->numSym = ::shl_getsymbols(mod->dsc.handle, TYPE_PROCEDURE, EXPORT_SYMBOLS, malloc, &mod->sym);
95 *handle = mod;
96 }
97 }
98 #endif
99 #endif
100 if ( 0 == *handle ) {
101 return System::getLastError();
102 }
103 return 1;
104 }
105
106 static unsigned long loadWithoutEnvironment(const std::string& name, System::ImageHandle* handle) {
107
108 std::string dllName = name;
109 long len = strlen(SHLIB_SUFFIX);
110
111 // Add the suffix at the end of the library name only if necessary
112 // FIXME: cure the logic
113 if ((dllName.length() != 0) &&
114 ::strncasecmp(dllName.data()+dllName.length()-len, SHLIB_SUFFIX, len) != 0) {
115 dllName += SHLIB_SUFFIX;
116 }
117
118 // Load the library
119 return doLoad(dllName, handle);
120 }
121
123 unsigned long System::loadDynamicLib(const std::string& name, ImageHandle* handle) {
124 unsigned long res;
125 // if name is empty, just load it
126 if (name.length() == 0) {
127 res = loadWithoutEnvironment(name, handle);
128 } else {
129 // If the name is a logical name (environment variable), the try
130 // to load the corresponding library from there.
131 std::string imgName;
132 if ( getEnv(name, imgName) ) {
133 res = loadWithoutEnvironment(imgName, handle);
134 } else {
135 // build the dll name
136 std::string dllName = name;
137 // if the lib name contains '/' we can assume is the path to a file
138 // (relative or absolute), otherwise it might be a logical library name
139 // (i.e. without 'lib' and '.so')
140 if (dllName.find('/') == std::string::npos) {
141 #if defined(__linux) || defined(__APPLE__)
142 if (dllName.substr(0, 3) != "lib")
143 dllName = "lib" + dllName;
144 #endif
145 if (dllName.find(SHLIB_SUFFIX) == std::string::npos)
146 dllName += SHLIB_SUFFIX;
147 }
148 // try to locate the dll using the standard PATH
149 res = loadWithoutEnvironment(dllName, handle);
150 }
151 if ( res != 1 ) {
152 #if defined(__linux) || defined(__APPLE__)
153 errno = 0xAFFEDEAD;
154 #endif
155 // std::cout << "System::loadDynamicLib>" << getLastErrorString() << std::endl;
156 }
157 }
158 return res;
159 }
160
162 unsigned long System::unloadDynamicLib(ImageHandle handle) {
163 #ifdef _WIN32
164 if ( !::FreeLibrary((HINSTANCE)handle) ) {
165 #elif defined(__linux) || defined(__APPLE__)
166 ::dlclose( handle );
167 if ( 0 ) {
168 #elif __hpux
169 // On HP we have to run finalization ourselves.....
170 Creator pFinalize = 0;
171 if ( getProcedureByName(handle, "_fini", &pFinalize) ) {
172 pFinalize();
173 }
174 HMODULE* mod = (HMODULE*)handle;
175 if ( 0 == ::shl_unload( mod->dsc.handle ) ) {
176 delete mod;
177 }
178 else {
179 #else
180 if (false){
181 #endif
182 return getLastError();
183 }
184 return 1;
185 }
186
188 unsigned long System::getProcedureByName(ImageHandle handle, const std::string& name, EntryPoint* pFunction) {
189 #ifdef _WIN32
190 *pFunction = (EntryPoint)::GetProcAddress((HINSTANCE)handle, name.data());
191 if ( 0 == *pFunction ) {
192 return System::getLastError();
193 }
194 return 1;
195 #elif defined(__linux)
196 #if __GNUC__ < 4
197 *pFunction = (EntryPoint)::dlsym(handle, name.c_str());
198 #else
199 *pFunction = FuncPtrCast<EntryPoint>(::dlsym(handle, name.c_str()));
200 #endif
201 if ( 0 == *pFunction ) {
202 errno = 0xAFFEDEAD;
203 // std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
204 return 0;
205 }
206 return 1;
207 #elif defined(__APPLE__)
208 *pFunction = (EntryPoint)::dlsym(handle, name.c_str());
209 if(!(*pFunction)) {
210 // Try with an underscore :
211 std::string sname = "_" + name;
212 *pFunction = (EntryPoint)::dlsym(handle, sname.c_str());
213 }
214 if ( 0 == *pFunction ) {
215 errno = 0xAFFEDEAD;
216 std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
217 //std::cout << "System::getProcedureByName> failure" << std::endl;
218 return 0;
219 }
220 return 1;
221 #elif __hpux
222 HMODULE* mod = (HMODULE*)handle;
223 if ( 0 != mod ) {
224 long ll1 = name.length();
225 for ( int i = 0; i < mod->numSym; i++ ) {
226 long ll2 = strlen(mod->sym[i].name);
227 if ( 0 != ::strncmp(mod->sym[i].name, name.c_str(), (ll1>ll2) ? ll1 : ll2)==0 ) {
228 *pFunction = (EntryPoint) mod->sym[i].value;
229 return 1;
230 }
231 }
232 }
233 return 0;
234 #endif
235 }
236
238 unsigned long System::getProcedureByName(ImageHandle handle, const std::string& name, Creator* pFunction) {
239 return getProcedureByName(handle, name, (EntryPoint*)pFunction);
240 }
241
243 unsigned long System::getLastError() {
244 #ifdef _WIN32
245 return ::GetLastError();
246 #else
247 // convert errno (int) to unsigned long
248 return static_cast<unsigned long>(static_cast<unsigned int>(errno));
249 #endif
250 }
251
253 const std::string System::getLastErrorString() {
254 const std::string errString = getErrorString(getLastError());
255 return errString;
256 }
257
259 const std::string System::getErrorString(unsigned long error) {
260 std::string errString = "";
261 #ifdef _WIN32
262 LPVOID lpMessageBuffer;
263 ::FormatMessage(
264 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
265 NULL,
266 error,
267 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language
268 (LPTSTR) &lpMessageBuffer,
269 0,
270 NULL );
271 errString = (const char*)lpMessageBuffer;
272 // Free the buffer allocated by the system
273 ::LocalFree( lpMessageBuffer );
274 #else
275 char *cerrString(0);
276 // Remember: for linux dl* routines must be handled differently!
277 if ( error == 0xAFFEDEAD ) {
278 cerrString = (char*)::dlerror();
279 if ( 0 == cerrString ) {
280 cerrString = ::strerror(error);
281 }
282 if ( 0 == cerrString ) {
283 cerrString = (char *)"Unknown error. No information found in strerror()!";
284 }
285 else {
286 errString = std::string(cerrString);
287 }
288 errno = 0;
289 }
290 else {
291 cerrString = ::strerror(error);
292 errString = std::string(cerrString);
293 }
294 #endif
295 return errString;
296 }
297
298 const std::string System::typeinfoName( const std::type_info& tinfo) {
299 return typeinfoName(tinfo.name());
300 }
301
302 const std::string System::typeinfoName( const char* class_name) {
303 std::string result;
304 #ifdef _WIN32
305 long off = 0;
306 if ( ::strncmp(class_name, "class ", 6) == 0 ) {
307 // The returned name is prefixed with "class "
308 off = 6;
309 }
310 if ( ::strncmp(class_name, "struct ", 7) == 0 ) {
311 // The returned name is prefixed with "struct "
312 off = 7;
313 }
314 if ( off > 0 ) {
315 std::string tmp = class_name + off;
316 long loc = 0;
317 while( (loc = tmp.find("class ")) > 0 ) {
318 tmp.erase(loc, 6);
319 }
320 loc = 0;
321 while( (loc = tmp.find("struct ")) > 0 ) {
322 tmp.erase(loc, 7);
323 }
324 result = tmp;
325 }
326 else {
327 result = class_name;
328 }
329 // Change any " *" to "*"
330 while ( (off=result.find(" *")) != std::string::npos ) {
331 result.replace(off, 2, "*");
332 }
333 // Change any " &" to "&"
334 while ( (off=result.find(" &")) != std::string::npos ) {
335 result.replace(off, 2, "&");
336 }
337
338 #elif defined(__linux) || defined(__APPLE__)
339 if ( ::strlen(class_name) == 1 ) {
340 // See http://www.realitydiluted.com/mirrors/reality.sgi.com/dehnert_engr/cxx/abi.pdf
341 // for details
342 switch(class_name[0]) {
343 case 'v':
344 result = "void";
345 break;
346 case 'w':
347 result = "wchar_t";
348 break;
349 case 'b':
350 result = "bool";
351 break;
352 case 'c':
353 result = "char";
354 break;
355 case 'a':
356 result = "signed char";
357 break;
358 case 'h':
359 result = "unsigned char";
360 break;
361 case 's':
362 result = "short";
363 break;
364 case 't':
365 result = "unsigned short";
366 break;
367 case 'i':
368 result = "int";
369 break;
370 case 'j':
371 result = "unsigned int";
372 break;
373 case 'l':
374 result = "long";
375 break;
376 case 'm':
377 result = "unsigned long";
378 break;
379 case 'x':
380 result = "long long";
381 break;
382 case 'y':
383 result = "unsigned long long";
384 break;
385 case 'n':
386 result = "__int128";
387 break;
388 case 'o':
389 result = "unsigned __int128";
390 break;
391 case 'f':
392 result = "float";
393 break;
394 case 'd':
395 result = "double";
396 break;
397 case 'e':
398 result = "long double";
399 break;
400 case 'g':
401 result = "__float128";
402 break;
403 case 'z':
404 result = "ellipsis";
405 break;
406 }
407 }
408 else {
409 int status;
410 char* realname;
411 realname = abi::__cxa_demangle(class_name, 0, 0, &status);
412 if (realname == 0) return class_name;
413 result = realname;
414 free(realname);
416 std::string::size_type pos = result.find(", ");
417 while( std::string::npos != pos ) {
418 result.replace( pos , 2 , "," ) ;
419 pos = result.find(", ");
420 }
421 }
422 #endif
423 return result;
424 }
425
427 const std::string& System::hostName() {
428 static std::string host = "";
429 if ( host == "" ) {
430 char buffer[512];
431 memset(buffer,0,sizeof(buffer));
432 #ifdef _WIN32
433 unsigned long len = sizeof(buffer);
434 ::GetComputerName(buffer, &len);
435 #else
436 ::gethostname(buffer, sizeof(buffer));
437 #endif
438 host = buffer;
439 }
440 return host;
441 }
442
444 const std::string& System::osName() {
445 static std::string osname = "";
446 #ifdef _WIN32
447 osname = "Windows";
448 #else
449 struct utsname ut;
450 if (uname(&ut) == 0) {
451 osname = ut.sysname;
452 } else {
453 osname = "UNKNOWN";
454 }
455 #endif
456 return osname;
457 }
458
459
461 const std::string& System::osVersion() {
462 static std::string osver = "";
463 #ifdef _WIN32
464 OSVERSIONINFO ut;
465 ut.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
466 ::GetVersionEx(&ut);
467 std::ostringstream ver;
468 ver << ut.dwMajorVersion << '.' << ut.dwMinorVersion;
469 osver = ver.str();
470 #else
471 struct utsname ut;
472 if (uname(&ut) == 0) {
473 osver = ut.release;
474 } else {
475 osver = "UNKNOWN";
476 }
477 #endif
478 return osver;
479 }
480
482 const std::string& System::machineType() {
483 static std::string mach = "";
484 #ifdef _WIN32
485 SYSTEM_INFO ut;
486 ::GetSystemInfo(&ut);
487 std::ostringstream arch;
488 arch << ut.wProcessorArchitecture;
489 mach = arch.str();
490 #else
491 struct utsname ut;
492 if (uname(&ut) == 0) {
493 mach = ut.machine;
494 } else {
495 mach = "UNKNOWN";
496 }
497 #endif
498 return mach;
499 }
500
502 const std::string& System::accountName() {
503 static std::string account = "";
504 if ( account == "" ) {
505 #ifdef _WIN32
506 char buffer[512];
507 unsigned long buflen = sizeof(buffer);
508 ::GetUserName(buffer, &buflen);
509 account = buffer;
510 #else
511 const char* acct = ::getlogin();
512 if ( 0 == acct ) acct = ::getenv("LOGNAME");
513 if ( 0 == acct ) acct = ::getenv("USER");
514 account = (acct) ? acct : "Unknown";
515 #endif
516 }
517 return account;
518 }
519
521 long System::numCmdLineArgs() {
522 return cmdLineArgs().size();
523 }
524
526 long System::argc() {
527 return cmdLineArgs().size();
528 }
529
531 const std::vector<std::string> System::cmdLineArgs() {
532 if ( s_argvChars.size() == 0 ) {
533 char exe[1024];
534 #ifdef _WIN32
535
536 // Disable warning C4996 triggered by C standard library calls
537 #pragma warning(push)
538 #pragma warning(disable:4996)
539 // For compatibility with UNIX we CANNOT use strtok!
540 // If we would use strtok, options like -g="My world" at
541 // the command line level would result on NT in TWO options
542 // instead in one as in UNIX.
543 char *next, *tmp1, *tmp2;
544 for(LPTSTR cmd = ::GetCommandLine(); *cmd; cmd=next) {
545 memset(exe,0,sizeof(exe));
546 while ( *cmd == ' ' ) cmd++;
547 next=::strchr(cmd,' ');
548 if ( !next ) next = cmd + strlen(cmd);
549 if ( (tmp1=::strchr(cmd,'\"')) > 0 && tmp1 < next ) {
550 tmp2 = ::strchr(++tmp1,'\"');
551 if ( tmp2 > 0 ) {
552 next = ++tmp2;
553 if ( cmd < tmp1 ) strncpy(exe, cmd, tmp1-cmd-1);
554 strncpy(&exe[strlen(exe)], tmp1, tmp2-tmp1-1);
555 }
556 else {
557 std::cout << "Mismatched \" in command line arguments" << std::endl;
558 s_argvChars.erase(s_argvChars.begin(), s_argvChars.end());
559 s_argvStrings.erase(s_argvStrings.begin(), s_argvStrings.end());
560 return s_argvStrings;
561 }
562 }
563 else {
564 strncpy(exe, cmd, next-cmd);
565 }
566 s_argvStrings.push_back(exe);
567 s_argvChars.push_back( s_argvStrings.back().c_str());
568 }
569 #pragma warning(pop)
570 #elif defined(__linux) || defined(__APPLE__)
571 sprintf(exe, "/proc/%d/cmdline", ::getpid());
572 FILE *cmdLine = ::fopen(exe,"r");
573 char cmd[1024];
574 if ( cmdLine ) {
575 long len = fread(cmd, sizeof(char), sizeof(cmd), cmdLine);
576 if ( len > 0 ) {
577 cmd[len] = 0;
578 for ( char* token = cmd; token-cmd < len; token += strlen(token)+1 ) {
579 s_argvStrings.push_back(token);
580 s_argvChars.push_back( s_argvStrings.back().c_str());
581 }
582 s_argvStrings[0] = exeName();
583 s_argvChars[0] = s_argvStrings[0].c_str();
584 }
585 ::fclose(cmdLine);
586 }
587 #endif
588 }
589 return s_argvStrings;
590 }
591
593 char** System::argv() {
595 if( s_argvChars.empty() ) { cmdLineArgs(); }
596
597 // We rely here on the fact that a vector's allocation table is contiguous
598 return (char**)&s_argvChars[0];
599 }
600
601 #ifdef WIN32
602 // disable warning
603 // C4996: 'getenv': This function or variable may be unsafe.
604 #pragma warning(disable:4996)
605 #endif
606
608 std::string System::getEnv(const char* var) {
609 char* env;
610 if ( (env = getenv(var)) != 0 ) {
611 return env;
612 } else {
613 return "UNKNOWN";
614 }
615 }
616
618 bool System::getEnv(const char* var, std::string &value) {
619 char* env;
620 if ( (env = getenv(var)) != 0 ) {
621 value = env;
622 return true;
623 } else {
624 return false;
625 }
626 }
627
628 bool System::isEnvSet(const char* var) {
629 return getenv(var) != 0;
630 }
631
633 #if defined(__APPLE__)
634 // Needed for _NSGetEnviron(void)
635 #include "crt_externs.h"
636 #endif
637 std::vector<std::string> System::getEnv() {
638 #if defined(_WIN32)
639 # define environ _environ
640 #elif defined(__APPLE__)
641 static char **environ = *_NSGetEnviron();
642 #endif
643 std::vector<std::string> vars;
644 for (int i=0; environ[i] != 0; ++i) {
645 vars.push_back(environ[i]);
646 }
647 return vars;
648 }
649
650 // -----------------------------------------------------------------------------
651 // backtrace utilities
652 // -----------------------------------------------------------------------------
653 #ifdef __linux
654 #include <execinfo.h>
655 #endif
656
657 int System::backTrace(void** addresses __attribute__ ((unused)),
658 const int depth __attribute__ ((unused)))
659 {
660
661 #ifdef __linux
662
663 int count = backtrace( addresses, depth );
664 if ( count > 0 ) {
665 return count;
666 } else {
667 return 0;
668 }
669
670 #else // windows and osx parts not implemented
671 return 0;
672 #endif
673
674 }
675
676 bool System::backTrace(std::string& btrace, const int depth, const int offset)
677 {
678 // Always hide the first two levels of the stack trace (that's us)
679 const int totalOffset = offset + 2;
680 const int totalDepth = depth + totalOffset;
681
682 std::string fnc, lib;
683
684 void** addresses = (void**) malloc(totalDepth*sizeof(void *));
685 if ( addresses != 0 ){
686 int count = System::backTrace(addresses,totalDepth);
687 for (int i = totalOffset; i < count; ++i) {
688 void *addr = 0;
689
690 if (System::getStackLevel(addresses[i],addr,fnc,lib)) {
691 std::ostringstream ost;
692 ost << "#" << std::setw(3) << std::setiosflags( std::ios::left ) << i-totalOffset+1;
693 ost << std::hex << addr << std::dec << " " << fnc << " [" << lib << "]" << std::endl;
694 btrace += ost.str();
695 }
696 }
697 free(addresses);
698 }
699 else {
700 free(addresses);
701 return false;
702 }
703
704 return true;
705 }
706
707 bool System::getStackLevel(void* addresses __attribute__ ((unused)),
708 void*& addr __attribute__ ((unused)),
709 std::string& fnc __attribute__ ((unused)),
710 std::string& lib __attribute__ ((unused)))
711 {
712
713 #ifdef __linux
714
715 Dl_info info;
716
717 if ( dladdr( addresses, &info ) && info.dli_fname
718 && info.dli_fname[0] != '\0' ) {
719 const char* symbol = info.dli_sname
720 && info.dli_sname[0] != '\0' ? info.dli_sname : 0;
721
722 lib = info.dli_fname;
723 addr = info.dli_saddr;
724 const char* dmg(0);
725
726 if (symbol != 0) {
727 int stat;
728 dmg = abi::__cxa_demangle(symbol,0,0,&stat);
729 fnc = (stat == 0) ? dmg : symbol;
730 } else {
731 fnc = "local";
732 }
733 free((void*)dmg);
734 return true ;
735 } else {
736 return false ;
737 }
738
739 #else // not implemented for windows and osx
740 return false ;
741 #endif
742
743 }
744
746 int System::setEnv(const std::string &name, const std::string &value, int overwrite)
747 {
748 #ifndef WIN32
749 // UNIX version
750 return value.empty() ?
751 // remove if set to nothing (and return success)
752 ::unsetenv(name.c_str()) , 0 :
753 // set the value
754 ::setenv(name.c_str(),value.c_str(), overwrite);
755 #else
756 // Windows version
757 if ( value.empty() ) {
758 // equivalent to unsetenv
759 return ::_putenv((name+"=").c_str());
760 }
761 else {
762 if ( !getenv(name.c_str()) || overwrite ) {
763 // set if not yet present or overwrite is set (force)
764 return ::_putenv((name+"="+value).c_str());
765 }
766 }
767 return 0; // if we get here, we are trying to set a variable already set, but
768 // not to overwrite.
769 // It is considered a success on Linux (man P setenv)
770 #endif
771
772 }