Gaudi Framework, version v23r6

Home   Generated: Wed Jan 30 2013
 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 
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 defined(linux) || defined(__APPLE__)
138  dllName = "lib" + dllName;
139 #endif
140  dllName += SHLIB_SUFFIX;
141  // try to locate the dll using the standard PATH
142  res = loadWithoutEnvironment(dllName, handle);
143  }
144  if ( res != 1 ) {
145 #if defined(linux) || defined(__APPLE__)
146  errno = 0xAFFEDEAD;
147 #endif
148  // std::cout << "System::loadDynamicLib>" << getLastErrorString() << std::endl;
149  }
150  }
151  return res;
152 }
153 
155 unsigned long System::unloadDynamicLib(ImageHandle handle) {
156 #ifdef _WIN32
157  if ( !::FreeLibrary((HINSTANCE)handle) ) {
158 #elif defined(linux) || defined(__APPLE__)
159  ::dlclose( handle );
160  if ( 0 ) {
161 #elif __hpux
162  // On HP we have to run finalization ourselves.....
163  Creator pFinalize = 0;
164  if ( getProcedureByName(handle, "_fini", &pFinalize) ) {
165  pFinalize();
166  }
167  HMODULE* mod = (HMODULE*)handle;
168  if ( 0 == ::shl_unload( mod->dsc.handle ) ) {
169  delete mod;
170  }
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 #ifdef _WIN32
183  *pFunction = (EntryPoint)::GetProcAddress((HINSTANCE)handle, name.data());
184  if ( 0 == *pFunction ) {
185  return System::getLastError();
186  }
187  return 1;
188 #elif defined(linux)
189 #if __GNUC__ < 4
190  *pFunction = (EntryPoint)::dlsym(handle, name.c_str());
191 #else
192  *pFunction = FuncPtrCast<EntryPoint>(::dlsym(handle, name.c_str()));
193 #endif
194  if ( 0 == *pFunction ) {
195  errno = 0xAFFEDEAD;
196  // std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
197  return 0;
198  }
199  return 1;
200 #elif defined(__APPLE__)
201  *pFunction = (EntryPoint)::dlsym(handle, name.c_str());
202  if(!(*pFunction)) {
203  // Try with an underscore :
204  std::string sname = "_" + name;
205  *pFunction = (EntryPoint)::dlsym(handle, sname.c_str());
206  }
207  if ( 0 == *pFunction ) {
208  errno = 0xAFFEDEAD;
209  std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
210  //std::cout << "System::getProcedureByName> failure" << std::endl;
211  return 0;
212  }
213  return 1;
214 #elif __hpux
215  HMODULE* mod = (HMODULE*)handle;
216  if ( 0 != mod ) {
217  long ll1 = name.length();
218  for ( int i = 0; i < mod->numSym; i++ ) {
219  long ll2 = strlen(mod->sym[i].name);
220  if ( 0 != ::strncmp(mod->sym[i].name, name.c_str(), (ll1>ll2) ? ll1 : ll2)==0 ) {
221  *pFunction = (EntryPoint) mod->sym[i].value;
222  return 1;
223  }
224  }
225  }
226  return 0;
227 #endif
228 }
229 
231 unsigned long System::getProcedureByName(ImageHandle handle, const std::string& name, Creator* pFunction) {
232  return getProcedureByName(handle, name, (EntryPoint*)pFunction);
233 }
234 
236 unsigned long System::getLastError() {
237 #ifdef _WIN32
238  return ::GetLastError();
239 #else
240  // convert errno (int) to unsigned long
241  return static_cast<unsigned long>(static_cast<unsigned int>(errno));
242 #endif
243 }
244 
247  const std::string errString = getErrorString(getLastError());
248  return errString;
249 }
250 
252 const std::string System::getErrorString(unsigned long error) {
253  std::string errString = "";
254 #ifdef _WIN32
255  LPVOID lpMessageBuffer;
256  ::FormatMessage(
257  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
258  NULL,
259  error,
260  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language
261  (LPTSTR) &lpMessageBuffer,
262  0,
263  NULL );
264  errString = (const char*)lpMessageBuffer;
265  // Free the buffer allocated by the system
266  ::LocalFree( lpMessageBuffer );
267 #else
268  char *cerrString(0);
269  // Remember: for linux dl* routines must be handled differently!
270  if ( error == 0xAFFEDEAD ) {
271  cerrString = (char*)::dlerror();
272  if ( 0 == cerrString ) {
273  cerrString = ::strerror(error);
274  }
275  if ( 0 == cerrString ) {
276  cerrString = (char *)"Unknown error. No information found in strerror()!";
277  }
278  else {
279  errString = std::string(cerrString);
280  }
281  errno = 0;
282  }
283  else {
284  cerrString = ::strerror(error);
285  errString = std::string(cerrString);
286  }
287 #endif
288  return errString;
289 }
290 
292  return typeinfoName(tinfo.name());
293 }
294 
295 const std::string System::typeinfoName( const char* class_name) {
296  std::string result;
297 #ifdef _WIN32
298  long off = 0;
299  if ( ::strncmp(class_name, "class ", 6) == 0 ) {
300  // The returned name is prefixed with "class "
301  off = 6;
302  }
303  if ( ::strncmp(class_name, "struct ", 7) == 0 ) {
304  // The returned name is prefixed with "struct "
305  off = 7;
306  }
307  if ( off > 0 ) {
308  std::string tmp = class_name + off;
309  long loc = 0;
310  while( (loc = tmp.find("class ")) > 0 ) {
311  tmp.erase(loc, 6);
312  }
313  loc = 0;
314  while( (loc = tmp.find("struct ")) > 0 ) {
315  tmp.erase(loc, 7);
316  }
317  result = tmp;
318  }
319  else {
320  result = class_name;
321  }
322  // Change any " *" to "*"
323  while ( (off=result.find(" *")) != std::string::npos ) {
324  result.replace(off, 2, "*");
325  }
326  // Change any " &" to "&"
327  while ( (off=result.find(" &")) != std::string::npos ) {
328  result.replace(off, 2, "&");
329  }
330 
331 #elif defined(__linux) || defined(__APPLE__)
332  if ( ::strlen(class_name) == 1 ) {
333  // See http://www.realitydiluted.com/mirrors/reality.sgi.com/dehnert_engr/cxx/abi.pdf
334  // for details
335  switch(class_name[0]) {
336  case 'v':
337  result = "void";
338  break;
339  case 'w':
340  result = "wchar_t";
341  break;
342  case 'b':
343  result = "bool";
344  break;
345  case 'c':
346  result = "char";
347  break;
348  case 'a':
349  result = "signed char";
350  break;
351  case 'h':
352  result = "unsigned char";
353  break;
354  case 's':
355  result = "short";
356  break;
357  case 't':
358  result = "unsigned short";
359  break;
360  case 'i':
361  result = "int";
362  break;
363  case 'j':
364  result = "unsigned int";
365  break;
366  case 'l':
367  result = "long";
368  break;
369  case 'm':
370  result = "unsigned long";
371  break;
372  case 'x':
373  result = "long long";
374  break;
375  case 'y':
376  result = "unsigned long long";
377  break;
378  case 'n':
379  result = "__int128";
380  break;
381  case 'o':
382  result = "unsigned __int128";
383  break;
384  case 'f':
385  result = "float";
386  break;
387  case 'd':
388  result = "double";
389  break;
390  case 'e':
391  result = "long double";
392  break;
393  case 'g':
394  result = "__float128";
395  break;
396  case 'z':
397  result = "ellipsis";
398  break;
399  }
400  }
401  else {
402  int status;
403  char* realname;
404  realname = abi::__cxa_demangle(class_name, 0, 0, &status);
405  if (realname == 0) return class_name;
406  result = realname;
407  free(realname);
409  std::string::size_type pos = result.find(", ");
410  while( std::string::npos != pos ) {
411  result.replace( pos , 2 , "," ) ;
412  pos = result.find(", ");
413  }
414  }
415 #endif
416  return result;
417 }
418 
421  static std::string host = "";
422  if ( host == "" ) {
423  char buffer[512];
424  memset(buffer,0,sizeof(buffer));
425 #ifdef _WIN32
426  unsigned long len = sizeof(buffer);
427  ::GetComputerName(buffer, &len);
428 #else
429  ::gethostname(buffer, sizeof(buffer));
430 #endif
431  host = buffer;
432  }
433  return host;
434 }
435 
438  static std::string osname = "";
439 #ifdef _WIN32
440  osname = "Windows";
441 #else
442  struct utsname ut;
443  if (uname(&ut) == 0) {
444  osname = ut.sysname;
445  } else {
446  osname = "UNKNOWN";
447  }
448 #endif
449  return osname;
450 }
451 
452 
455  static std::string osver = "";
456 #ifdef _WIN32
457  OSVERSIONINFO ut;
458  ut.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
459  ::GetVersionEx(&ut);
460  std::ostringstream ver;
461  ver << ut.dwMajorVersion << '.' << ut.dwMinorVersion;
462  osver = ver.str();
463 #else
464  struct utsname ut;
465  if (uname(&ut) == 0) {
466  osver = ut.release;
467  } else {
468  osver = "UNKNOWN";
469  }
470 #endif
471  return osver;
472 }
473 
476  static std::string mach = "";
477 #ifdef _WIN32
478  SYSTEM_INFO ut;
479  ::GetSystemInfo(&ut);
480  std::ostringstream arch;
481  arch << ut.wProcessorArchitecture;
482  mach = arch.str();
483 #else
484  struct utsname ut;
485  if (uname(&ut) == 0) {
486  mach = ut.machine;
487  } else {
488  mach = "UNKNOWN";
489  }
490 #endif
491  return mach;
492 }
493 
496  static std::string account = "";
497  if ( account == "" ) {
498 #ifdef _WIN32
499  char buffer[512];
500  unsigned long buflen = sizeof(buffer);
501  ::GetUserName(buffer, &buflen);
502  account = buffer;
503 #else
504  const char* acct = ::getlogin();
505  if ( 0 == acct ) acct = ::getenv("LOGNAME");
506  if ( 0 == acct ) acct = ::getenv("USER");
507  account = (acct) ? acct : "Unknown";
508 #endif
509  }
510  return account;
511 }
512 
515  return cmdLineArgs().size();
516 }
517 
519 long System::argc() {
520  return cmdLineArgs().size();
521 }
522 
525  if ( s_argvChars.size() == 0 ) {
526  char exe[1024];
527 #ifdef _WIN32
528 
529  // Disable warning C4996 triggered by C standard library calls
530 #pragma warning(push)
531 #pragma warning(disable:4996)
532  // For compatibility with UNIX we CANNOT use strtok!
533  // If we would use strtok, options like -g="My world" at
534  // the command line level would result on NT in TWO options
535  // instead in one as in UNIX.
536  char *next, *tmp1, *tmp2;
537  for(LPTSTR cmd = ::GetCommandLine(); *cmd; cmd=next) {
538  memset(exe,0,sizeof(exe));
539  while ( *cmd == ' ' ) cmd++;
540  next=::strchr(cmd,' ');
541  if ( !next ) next = cmd + strlen(cmd);
542  if ( (tmp1=::strchr(cmd,'\"')) > 0 && tmp1 < next ) {
543  tmp2 = ::strchr(++tmp1,'\"');
544  if ( tmp2 > 0 ) {
545  next = ++tmp2;
546  if ( cmd < tmp1 ) strncpy(exe, cmd, tmp1-cmd-1);
547  strncpy(&exe[strlen(exe)], tmp1, tmp2-tmp1-1);
548  }
549  else {
550  std::cout << "Mismatched \" in command line arguments" << std::endl;
551  s_argvChars.erase(s_argvChars.begin(), s_argvChars.end());
552  s_argvStrings.erase(s_argvStrings.begin(), s_argvStrings.end());
553  return s_argvStrings;
554  }
555  }
556  else {
557  strncpy(exe, cmd, next-cmd);
558  }
559  s_argvStrings.push_back(exe);
560  s_argvChars.push_back( s_argvStrings.back().c_str());
561  }
562 #pragma warning(pop)
563 #elif defined(linux) || defined(__APPLE__)
564  sprintf(exe, "/proc/%d/cmdline", ::getpid());
565  FILE *cmdLine = ::fopen(exe,"r");
566  char cmd[1024];
567  if ( cmdLine ) {
568  long len = fread(cmd, sizeof(char), sizeof(cmd), cmdLine);
569  if ( len > 0 ) {
570  cmd[len] = 0;
571  for ( char* token = cmd; token-cmd < len; token += strlen(token)+1 ) {
572  s_argvStrings.push_back(token);
573  s_argvChars.push_back( s_argvStrings.back().c_str());
574  }
575  s_argvStrings[0] = exeName();
576  s_argvChars[0] = s_argvStrings[0].c_str();
577  }
578  }
579  ::fclose(cmdLine);
580 #endif
581  }
582  return s_argvStrings;
583 }
584 
586 char** System::argv() {
588  if( s_argvChars.empty() ) { cmdLineArgs(); }
589 
590  // We rely here on the fact that a vector's allocation table is contiguous
591  return (char**)&s_argvChars[0];
592 }
593 
594 #ifdef WIN32
595 // disable warning
596 // C4996: 'getenv': This function or variable may be unsafe.
597 #pragma warning(disable:4996)
598 #endif
599 
601 std::string System::getEnv(const char* var) {
602  char* env;
603  if ( (env = getenv(var)) != 0 ) {
604  return env;
605  } else {
606  return "UNKNOWN";
607  }
608 }
609 
611 bool System::getEnv(const char* var, std::string &value) {
612  char* env;
613  if ( (env = getenv(var)) != 0 ) {
614  value = env;
615  return true;
616  } else {
617  return false;
618  }
619 }
620 
621 bool System::isEnvSet(const char* var) {
622  return getenv(var) != 0;
623 }
624 
626 #if defined(__APPLE__)
627 // Needed for _NSGetEnviron(void)
628 #include "crt_externs.h"
629 #endif
631 #if defined(_WIN32)
632 # define environ _environ
633 #elif defined(__APPLE__)
634  static char **environ = *_NSGetEnviron();
635 #endif
637  for (int i=0; environ[i] != 0; ++i) {
638  vars.push_back(environ[i]);
639  }
640  return vars;
641 }
642 
643 // -----------------------------------------------------------------------------
644 // backtrace utilities
645 // -----------------------------------------------------------------------------
646 #ifdef __linux
647 #include <execinfo.h>
648 #endif
649 
650 int System::backTrace(void** addresses __attribute__ ((unused)),
651  const int depth __attribute__ ((unused)))
652 {
653 
654 #ifdef __linux
655 
656  int count = backtrace( addresses, depth );
657  if ( count > 0 ) {
658  return count;
659  } else {
660  return 0;
661  }
662 
663 #else // windows and osx parts not implemented
664  return 0;
665 #endif
666 
667 }
668 
669 bool System::backTrace(std::string& btrace, const int depth, const int offset)
670 {
671  // Always hide the first two levels of the stack trace (that's us)
672  const int totalOffset = offset + 2;
673  const int totalDepth = depth + totalOffset;
674 
675  std::string fnc, lib;
676 
677  void** addresses = (void**) malloc(totalDepth*sizeof(void *));
678  if ( addresses != 0 ){
679  int count = System::backTrace(addresses,totalDepth);
680  for (int i = totalOffset; i < count; ++i) {
681  void *addr = 0;
682 
683  if (System::getStackLevel(addresses[i],addr,fnc,lib)) {
684  std::ostringstream ost;
685  ost << "#" << std::setw(3) << std::setiosflags( std::ios::left ) << i-totalOffset+1;
686  ost << std::hex << addr << std::dec << " " << fnc << " [" << lib << "]" << std::endl;
687  btrace += ost.str();
688  }
689  }
690  free(addresses);
691  }
692  else {
693  free(addresses);
694  return false;
695  }
696 
697  return true;
698 }
699 
700 bool System::getStackLevel(void* addresses __attribute__ ((unused)),
701  void*& addr __attribute__ ((unused)),
702  std::string& fnc __attribute__ ((unused)),
703  std::string& lib __attribute__ ((unused)))
704 {
705 
706 #ifdef __linux
707 
708  Dl_info info;
709 
710  if ( dladdr( addresses, &info ) && info.dli_fname
711  && info.dli_fname[0] != '\0' ) {
712  const char* symbol = info.dli_sname
713  && info.dli_sname[0] != '\0' ? info.dli_sname : 0;
714 
715  lib = info.dli_fname;
716  addr = info.dli_saddr;
717  const char* dmg(0);
718 
719  if (symbol != 0) {
720  int stat;
721  dmg = abi::__cxa_demangle(symbol,0,0,&stat);
722  fnc = (stat == 0) ? dmg : symbol;
723  } else {
724  fnc = "local";
725  }
726  free((void*)dmg);
727  return true ;
728  } else {
729  return false ;
730  }
731 
732 #else // not implemented for windows and osx
733  return false ;
734 #endif
735 
736 }
737 
739 int System::setEnv(const std::string &name, const std::string &value, int overwrite)
740 {
741 #ifndef WIN32
742  // UNIX version
743  return value.empty() ?
744  // remove if set to nothing (and return success)
745  ::unsetenv(name.c_str()) , 0 :
746  // set the value
747  ::setenv(name.c_str(),value.c_str(), overwrite);
748 #else
749  // Windows version
750  if ( value.empty() ) {
751  // equivalent to unsetenv
752  return ::_putenv((name+"=").c_str());
753  }
754  else {
755  if ( !getenv(name.c_str()) || overwrite ) {
756  // set if not yet present or overwrite is set (force)
757  return ::_putenv((name+"="+value).c_str());
758  }
759  }
760  return 0; // if we get here, we are trying to set a variable already set, but
761  // not to overwrite.
762  // It is considered a success on Linux (man P setenv)
763 #endif
764 
765 }

Generated at Wed Jan 30 2013 17:13:40 for Gaudi Framework, version v23r6 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004