Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:57

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 // G4Backtrace
0027 //
0028 // Description:
0029 //
0030 //  Prints backtraces after signals are caught. Available on Unix.
0031 //
0032 // Usage:
0033 //  A standard set of signals are enabled by default:
0034 //
0035 //     SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
0036 //
0037 //  These should not interfere with debuggers and/or G4FPEDetection.
0038 //  In order to turn off handling for one or more signals, one can do:
0039 //
0040 //    G4Backtrace::DefaultSignals() = std::set<int>{};
0041 //    G4Backtrace::DefaultSignals() = std::set<int>{ SIGSEGV };
0042 //
0043 //  and so on, *before* creating the run-manager. After the run-manager
0044 //  has been created, one should disable the signals:
0045 //
0046 //    G4Backtrace::Disable(G4Backtrace::DefaultSignals());
0047 //
0048 //  Additionally, at runtime, the environment variable "G4BACKTRACE" can
0049 //  be set to select a specific set of signals or none, e.g. in bash:
0050 //
0051 //    export G4BACKTRACE="SIGQUIT,SIGSEGV"
0052 //    export G4BACKTRACE="none"
0053 //
0054 //  The environment variable is case-insensitive and can use any of the
0055 //  following delimiters: space, comma, semi-colon, colon
0056 //
0057 // Author: J.Madsen, 19 October 2020
0058 // --------------------------------------------------------------------
0059 
0060 #ifndef G4Backtrace_hh
0061 #define G4Backtrace_hh 1
0062 
0063 #include "G4Types.hh"
0064 #include "G4String.hh"
0065 #include "G4Threading.hh"
0066 
0067 #if defined(__APPLE__) || defined(__MACH__)
0068 #  if !defined(G4MACOS)
0069 #    define G4MACOS
0070 #  endif
0071 #  if !defined(G4UNIX)
0072 #    define G4UNIX
0073 #  endif
0074 #elif defined(__linux__) || defined(__linux) || defined(linux) ||              \
0075   defined(__gnu_linux__)
0076 #  if !defined(G4LINUX)
0077 #    define G4LINUX
0078 #  endif
0079 #  if !defined(G4UNIX)
0080 #    define G4UNIX
0081 #  endif
0082 #elif defined(__unix__) || defined(__unix) || defined(unix)
0083 #  if !defined(G4UNIX)
0084 #    define G4UNIX
0085 #  endif
0086 #endif
0087 
0088 #if defined(G4UNIX) && !defined(WIN32)
0089 #  include <cxxabi.h>
0090 #  include <execinfo.h>
0091 #  include <unistd.h>
0092 #endif
0093 
0094 #if defined(G4LINUX)
0095 #  include <features.h>
0096 #endif
0097 
0098 #include <cfenv>
0099 #include <csignal>
0100 #include <type_traits>
0101 
0102 template <typename FuncT, typename... ArgTypes>
0103 using G4ResultOf_t = std::invoke_result_t<FuncT, ArgTypes...>;
0104 
0105 // compatible OS and compiler
0106 #if defined(G4UNIX) &&                                                         \
0107   (defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER))
0108 #  if !defined(G4SIGNAL_AVAILABLE)
0109 #    define G4SIGNAL_AVAILABLE
0110 #  endif
0111 #  if !defined(G4DEMANGLE_AVAILABLE)
0112 #    define G4DEMANGLE_AVAILABLE
0113 #  endif
0114 #endif
0115 
0116 #if !defined(G4PSIGINFO_AVAILABLE)
0117 #  if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
0118 #    define G4PSIGINFO_AVAILABLE 1
0119 #  else
0120 #    define G4PSIGINFO_AVAILABLE 0
0121 #  endif
0122 #endif
0123 
0124 //----------------------------------------------------------------------------//
0125 
0126 inline G4String G4Demangle(const char* _str)
0127 {
0128 #if defined(G4DEMANGLE_AVAILABLE)
0129   // demangling a string when delimiting
0130   G4int _status = 0;
0131   char* _ret  = ::abi::__cxa_demangle(_str, nullptr, nullptr, &_status);
0132   if((_ret != nullptr) && _status == 0)
0133     return G4String(const_cast<const char*>(_ret));
0134   return _str;
0135 #else
0136   return _str;
0137 #endif
0138 }
0139 
0140 //----------------------------------------------------------------------------//
0141 
0142 inline G4String G4Demangle(const G4String& _str)
0143 {
0144   return G4Demangle(_str.c_str());
0145 }
0146 
0147 //----------------------------------------------------------------------------//
0148 
0149 template <typename Tp>
0150 inline G4String G4Demangle()
0151 {
0152   return G4Demangle(typeid(Tp).name());
0153 }
0154 
0155 //----------------------------------------------------------------------------//
0156 //
0157 //      ONLY IF G4SIGNAL_AVAILABLE
0158 //
0159 //----------------------------------------------------------------------------//
0160 //
0161 #if defined(G4SIGNAL_AVAILABLE)
0162 //
0163 //  these are not in the original POSIX.1-1990 standard so we are defining
0164 //  them in case the OS hasn't
0165 //  POSIX-1.2001
0166 #  ifndef SIGTRAP
0167 #    define SIGTRAP 5
0168 #  endif
0169 //  not specified in POSIX.1-2001, but nevertheless appears on most other
0170 //  UNIX systems, where its default action is typically to terminate the
0171 //  process with a core dump.
0172 #  ifndef SIGEMT
0173 #    define SIGEMT 7
0174 #  endif
0175 //  POSIX-1.2001
0176 #  ifndef SIGURG
0177 #    define SIGURG 16
0178 #  endif
0179 //  POSIX-1.2001
0180 #  ifndef SIGXCPU
0181 #    define SIGXCPU 24
0182 #  endif
0183 //  POSIX-1.2001
0184 #  ifndef SIGXFSZ
0185 #    define SIGXFSZ 25
0186 #  endif
0187 //  POSIX-1.2001
0188 #  ifndef SIGVTALRM
0189 #    define SIGVTALRM 26
0190 #  endif
0191 //  POSIX-1.2001
0192 #  ifndef SIGPROF
0193 #    define SIGPROF 27
0194 #  endif
0195 //  POSIX-1.2001
0196 #  ifndef SIGINFO
0197 #    define SIGINFO 29
0198 #  endif
0199 
0200 //----------------------------------------------------------------------------//
0201 
0202 #  include <algorithm>
0203 #  include <array>
0204 #  include <cstdlib>
0205 #  include <cstdio>
0206 #  include <functional>
0207 #  include <iomanip>
0208 #  include <iostream>
0209 #  include <map>
0210 #  include <regex>
0211 #  include <set>
0212 #  include <sstream>
0213 #  include <string>
0214 #  include <tuple>
0215 #  include <vector>
0216 
0217 //----------------------------------------------------------------------------//
0218 
0219 class G4Backtrace
0220 {
0221  public:
0222   using sigaction_t   = struct sigaction;
0223   using exit_action_t = std::function<void(G4int)>;
0224   using frame_func_t  = std::function<G4String(const char*)>;
0225   using signal_set_t  = std::set<G4int>;
0226 
0227  public:
0228   struct actions
0229   {
0230     using id_entry_t = std::tuple<std::string, G4int, std::string>;
0231     using id_list_t  = std::vector<id_entry_t>;
0232 
0233     std::map<G4int, G4bool> is_active           = {};
0234     std::map<G4int, sigaction_t> current      = {};
0235     std::map<G4int, sigaction_t> previous     = {};
0236     std::vector<exit_action_t> exit_actions = {};
0237     const id_list_t identifiers             = {
0238       id_entry_t("SIGHUP", SIGHUP, "terminal line hangup"),
0239       id_entry_t("SIGINT", SIGINT, "interrupt program"),
0240       id_entry_t("SIGQUIT", SIGQUIT, "quit program"),
0241       id_entry_t("SIGILL", SIGILL, "illegal instruction"),
0242       id_entry_t("SIGTRAP", SIGTRAP, "trace trap"),
0243       id_entry_t("SIGABRT", SIGABRT, "abort program (formerly SIGIOT)"),
0244       id_entry_t("SIGEMT", SIGEMT, "emulate instruction executed"),
0245       id_entry_t("SIGFPE", SIGFPE, "floating-point exception"),
0246       id_entry_t("SIGKILL", SIGKILL, "kill program"),
0247       id_entry_t("SIGBUS", SIGBUS, "bus error"),
0248       id_entry_t("SIGSEGV", SIGSEGV, "segmentation violation"),
0249       id_entry_t("SIGSYS", SIGSYS, "non-existent system call invoked"),
0250       id_entry_t("SIGPIPE", SIGPIPE, "write on a pipe with no reader"),
0251       id_entry_t("SIGALRM", SIGALRM, "real-time timer expired"),
0252       id_entry_t("SIGTERM", SIGTERM, "software termination signal"),
0253       id_entry_t("SIGURG", SIGURG, "urgent condition present on socket"),
0254       id_entry_t("SIGSTOP", SIGSTOP, "stop (cannot be caught or ignored)"),
0255       id_entry_t("SIGTSTP", SIGTSTP, "stop signal generated from keyboard"),
0256       id_entry_t("SIGCONT", SIGCONT, "continue after stop"),
0257       id_entry_t("SIGCHLD", SIGCHLD, "child status has changed"),
0258       id_entry_t("SIGTTIN", SIGTTIN,
0259                  "background read attempted from control terminal"),
0260       id_entry_t("SIGTTOU", SIGTTOU,
0261                  "background write attempted to control terminal"),
0262       id_entry_t("SIGIO ", SIGIO, "I/O is possible on a descriptor"),
0263       id_entry_t("SIGXCPU", SIGXCPU, "cpu time limit exceeded"),
0264       id_entry_t("SIGXFSZ", SIGXFSZ, "file size limit exceeded"),
0265       id_entry_t("SIGVTALRM", SIGVTALRM, "virtual time alarm"),
0266       id_entry_t("SIGPROF", SIGPROF, "profiling timer alarm"),
0267       id_entry_t("SIGWINCH", SIGWINCH, "Window size change"),
0268       id_entry_t("SIGINFO", SIGINFO, "status request from keyboard"),
0269       id_entry_t("SIGUSR1", SIGUSR1, "User defined signal 1"),
0270       id_entry_t("SIGUSR2", SIGUSR2, "User defined signal 2")
0271     };
0272   };
0273 
0274  public:
0275   // a functor called for each frame in the backtrace
0276   static frame_func_t& FrameFunctor();
0277   // default set of signals
0278   static signal_set_t& DefaultSignals();
0279   // the signal handler
0280   static void Handler(G4int sig, siginfo_t* sinfo, void* context);
0281   // information message about the signal, performs exit-actions
0282   // and prints back-trace
0283   static void Message(G4int sig, siginfo_t* sinfo, std::ostream&);
0284   // calls user-provided functions after signal is caught but before abort
0285   static void ExitAction(G4int sig);
0286   // enable signals via a string (which is tokenized)
0287   static G4int Enable(const std::string&);
0288   // enable signals via set of integers, anything less than zero is ignored
0289   static G4int Enable(const signal_set_t& _signals = DefaultSignals());
0290   // disable signals
0291   static G4int Disable(signal_set_t _signals = {});
0292   // gets the numeric value for a signal name
0293   static G4int GetSignal(const std::string&);
0294   // provides a description of the signal
0295   static std::string Description(G4int sig);
0296 
0297   // adds an exit action
0298   template <typename FuncT>
0299   static void AddExitAction(FuncT&& func);
0300 
0301   // gets a backtrace of "Depth" frames. The offset parameter is used
0302   // to ignore initial frames (such as this function). A callback
0303   // can be provided to inspect and/or tweak the frame string
0304   template <std::size_t Depth, std::size_t Offset = 0, typename FuncT = frame_func_t>
0305   static std::array<G4ResultOf_t<FuncT, const char*>, Depth> GetMangled(
0306     FuncT&& func = FrameFunctor());
0307 
0308   // gets a demangled backtrace of "Depth" frames. The offset parameter is
0309   // used to ignore initial frames (such as this function). A callback
0310   // can be provided to inspect and/or tweak the frame string
0311   template <std::size_t Depth, std::size_t Offset = 0, typename FuncT = frame_func_t>
0312   static std::array<G4ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
0313     FuncT&& func = FrameFunctor());
0314 
0315  private:
0316   static actions& GetData()
0317   {
0318     static auto _instance = actions{};
0319     return _instance;
0320   }
0321 };
0322 
0323 //----------------------------------------------------------------------------//
0324 
0325 // a functor called for each frame in the backtrace
0326 inline G4Backtrace::frame_func_t& G4Backtrace::FrameFunctor()
0327 {
0328   static frame_func_t _instance = [](const char* inp) { return G4String(inp); };
0329   return _instance;
0330 }
0331 
0332 //----------------------------------------------------------------------------//
0333 
0334 // default set of signals
0335 inline G4Backtrace::signal_set_t& G4Backtrace::DefaultSignals()
0336 {
0337   static signal_set_t _instance = { SIGQUIT, SIGILL, SIGABRT,
0338                                     SIGKILL, SIGBUS, SIGSEGV };
0339   return _instance;
0340 }
0341 
0342 //----------------------------------------------------------------------------//
0343 
0344 template <typename FuncT>
0345 inline void G4Backtrace::AddExitAction(FuncT&& func)
0346 {
0347   GetData().exit_actions.emplace_back(std::forward<FuncT>(func));
0348 }
0349 
0350 //----------------------------------------------------------------------------//
0351 
0352 inline void G4Backtrace::ExitAction(G4int sig)
0353 {
0354   for(auto& itr : GetData().exit_actions)
0355     itr(sig);
0356 }
0357 
0358 //----------------------------------------------------------------------------//
0359 
0360 template <std::size_t Depth, std::size_t Offset, typename FuncT>
0361 inline std::array<G4ResultOf_t<FuncT, const char*>, Depth>
0362 G4Backtrace::GetMangled(FuncT&& func)
0363 {
0364   static_assert((Depth - Offset) >= 1, "Error Depth - Offset should be >= 1");
0365 
0366   using type = G4ResultOf_t<FuncT, const char*>;
0367   // destination
0368   std::array<type, Depth> btrace;
0369   btrace.fill((std::is_pointer<type>::value) ? nullptr : type{});
0370 
0371   // plus one for this stack-frame
0372   std::array<void*, Depth + Offset> buffer;
0373   // size of returned buffer
0374   auto sz = backtrace(buffer.data(), Depth + Offset);
0375   // size of relevant data
0376   auto n = sz - Offset;
0377 
0378   // skip ahead (Offset + 1) stack frames
0379   char** bsym = backtrace_symbols(buffer.data() + Offset, (G4int)n);
0380 
0381   // report errors
0382   if(bsym == nullptr)
0383     perror("backtrace_symbols");
0384   else
0385   {
0386     for(decltype(n) i = 0; i < n; ++i)
0387       btrace[i] = func(bsym[i]);
0388     free(bsym);
0389   }
0390   return btrace;
0391 }
0392 
0393 //----------------------------------------------------------------------------//
0394 
0395 template <std::size_t Depth, std::size_t Offset, typename FuncT>
0396 inline std::array<G4ResultOf_t<FuncT, const char*>, Depth>
0397 G4Backtrace::GetDemangled(FuncT&& func)
0398 {
0399   auto demangle_bt = [&](const char* cstr) {
0400     auto _trim = [](std::string& _sub, std::size_t& _len) {
0401       std::size_t _pos = 0;
0402       while((_pos = _sub.find_first_of(' ')) == 0)
0403       {
0404         _sub = _sub.erase(_pos, 1);
0405         --_len;
0406       }
0407       while((_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
0408       {
0409         _sub = _sub.substr(0, _sub.length() - 1);
0410         --_len;
0411       }
0412       return _sub;
0413     };
0414 
0415     auto str = G4Demangle(std::string(cstr));
0416     auto beg = str.find('(');
0417     if(beg == std::string::npos)
0418     {
0419       beg = str.find("_Z");
0420       if(beg != std::string::npos)
0421         beg -= 1;
0422     }
0423     auto end = str.find('+', beg);
0424     if(beg != std::string::npos && end != std::string::npos)
0425     {
0426       auto len = end - (beg + 1);
0427       auto sub = str.substr(beg + 1, len);
0428       auto dem = G4Demangle(_trim(sub, len));
0429       str      = str.replace(beg + 1, len, dem);
0430     }
0431     else if(beg != std::string::npos)
0432     {
0433       auto len = str.length() - (beg + 1);
0434       auto sub = str.substr(beg + 1, len);
0435       auto dem = G4Demangle(_trim(sub, len));
0436       str      = str.replace(beg + 1, len, dem);
0437     }
0438     else if(end != std::string::npos)
0439     {
0440       auto len = end;
0441       auto sub = str.substr(beg, len);
0442       auto dem = G4Demangle(_trim(sub, len));
0443       str      = str.replace(beg, len, dem);
0444     }
0445     return func(str.c_str());
0446   };
0447   return GetMangled<Depth, Offset>(demangle_bt);
0448 }
0449 
0450 //----------------------------------------------------------------------------//
0451 
0452 inline void G4Backtrace::Message(G4int sig, siginfo_t* sinfo, std::ostream& os)
0453 {
0454   // try to avoid as many dynamic allocations as possible here to avoid
0455   // overflowing the signal stack
0456 
0457   // ignore future signals of this type
0458   signal(sig, SIG_IGN);
0459 
0460   os << "\n### CAUGHT SIGNAL: " << sig << " ### ";
0461   if(sinfo != nullptr)
0462     os << "address: " << sinfo->si_addr << ", ";
0463   os << Description(sig) << ". ";
0464 
0465   if(sig == SIGSEGV)
0466   {
0467     if(sinfo != nullptr)
0468     {
0469       switch(sinfo->si_code)
0470       {
0471         case SEGV_MAPERR:
0472           os << "Address not mapped to object.";
0473           break;
0474         case SEGV_ACCERR:
0475           os << "Invalid permissions for mapped object.";
0476           break;
0477         default:
0478           os << "Unknown segmentation fault error: " << sinfo->si_code << ".";
0479           break;
0480       }
0481     }
0482     else
0483     {
0484       os << "Segmentation fault (unknown).";
0485     }
0486   }
0487   else if(sig == SIGFPE)
0488   {
0489     if(sinfo != nullptr)
0490     {
0491       switch(sinfo->si_code)
0492       {
0493         case FE_DIVBYZERO:
0494           os << "Floating point divide by zero.";
0495           break;
0496         case FE_OVERFLOW:
0497           os << "Floating point overflow.";
0498           break;
0499         case FE_UNDERFLOW:
0500           os << "Floating point underflow.";
0501           break;
0502         case FE_INEXACT:
0503           os << "Floating point inexact result.";
0504           break;
0505         case FE_INVALID:
0506           os << "Floating point invalid operation.";
0507           break;
0508         default:
0509           os << "Unknown floating point exception error: " << sinfo->si_code
0510              << ".";
0511           break;
0512       }
0513     }
0514     else
0515     {
0516       os << "Unknown floating point exception";
0517       if(sinfo != nullptr)
0518         os << ": " << sinfo->si_code;
0519       os << ". ";
0520     }
0521   }
0522 
0523   os << '\n';
0524 
0525   auto bt = GetMangled<256, 3>([](const char* _s) { return _s; });
0526   char prefix[64];
0527   snprintf(prefix, 64, "[PID=%i, TID=%i]", (G4int) getpid(),
0528            (G4int) G4Threading::G4GetThreadId());
0529   std::size_t sz = 0;
0530   for(auto& itr : bt)
0531   {
0532     if(itr == nullptr)
0533       break;
0534     if(strlen(itr) == 0)
0535       break;
0536     ++sz;
0537   }
0538   os << "\nBacktrace:\n";
0539   auto _w = std::log10(sz) + 1;
0540   for(std::size_t i = 0; i < sz; ++i)
0541   {
0542     os << prefix << "[" << std::setw(_w) << std::right << i << '/'
0543        << std::setw(_w) << std::right << sz << "]> " << std::left << bt.at(i)
0544        << '\n';
0545   }
0546   os << std::flush;
0547 
0548   // exit action could cause more signals to be raise so make sure this is done
0549   // after the message has been printed
0550   try
0551   {
0552     ExitAction(sig);
0553   } catch(std::exception& e)
0554   {
0555     std::cerr << "ExitAction(" << sig << ") threw an exception" << std::endl;
0556     std::cerr << e.what() << std::endl;
0557   }
0558 }
0559 
0560 //----------------------------------------------------------------------------//
0561 
0562 inline void G4Backtrace::Handler(G4int sig, siginfo_t* sinfo, void*)
0563 {
0564   Message(sig, sinfo, std::cerr);
0565 
0566   char msg[1024];
0567   snprintf(msg, 1024, "%s", "\n");
0568 
0569   if((sinfo != nullptr) && G4PSIGINFO_AVAILABLE > 0)
0570   {
0571 #  if G4PSIGINFO_AVAILABLE > 0
0572     psiginfo(sinfo, msg);
0573     fflush(stdout);
0574     fflush(stderr);
0575 #  endif
0576   }
0577   else
0578   {
0579     std::cerr << msg << std::flush;
0580   }
0581 
0582   // ignore any termination signals
0583   signal(SIGKILL, SIG_IGN);
0584   signal(SIGTERM, SIG_IGN);
0585   signal(SIGABRT, SIG_IGN);
0586   abort();
0587 }
0588 
0589 //----------------------------------------------------------------------------//
0590 
0591 inline G4int G4Backtrace::Enable(const signal_set_t& _signals)
0592 {
0593   static G4bool _first = true;
0594   if(_first)
0595   {
0596     std::string _msg = "!!! G4Backtrace is activated !!!";
0597     std::stringstream _filler;
0598     std::stringstream _spacer;
0599     _filler.fill('#');
0600     _filler << std::setw((G4int)_msg.length()) << "";
0601     _spacer << std::setw(10) << "";
0602     std::cout << "\n\n"
0603               << _spacer.str() << _filler.str() << "\n"
0604               << _spacer.str() << _msg << "\n"
0605               << _spacer.str() << _filler.str() << "\n\n"
0606               << std::flush;
0607   }
0608   _first  = false;
0609   G4int cnt = 0;
0610   for(auto& itr : _signals)
0611   {
0612     if(itr < 0)
0613       continue;
0614     if(GetData().is_active[itr])
0615       continue;
0616     ++cnt;
0617     sigfillset(&(GetData().current[itr].sa_mask));
0618     sigdelset(&(GetData().current[itr].sa_mask), itr);
0619     GetData().current[itr].sa_sigaction = &Handler;
0620     GetData().current[itr].sa_flags     = SA_SIGINFO;
0621     sigaction(itr, &(GetData().current[itr]), &(GetData().previous[itr]));
0622   }
0623   return cnt;
0624 }
0625 
0626 //----------------------------------------------------------------------------//
0627 
0628 inline G4int G4Backtrace::Enable(const std::string& _signals)
0629 {
0630   if(_signals.empty())
0631     return 0;
0632 
0633   auto _add_signal = [](std::string sig, signal_set_t& _targ) {
0634     if(!sig.empty())
0635     {
0636       for(auto& itr : sig)
0637         itr = (char)std::toupper(itr);
0638       _targ.insert(G4Backtrace::GetSignal(sig));
0639     }
0640   };
0641 
0642   const std::regex wsp_re("[ ,;:\t\n]+");
0643   auto _maxid  = GetData().identifiers.size();
0644   auto _result = std::vector<std::string>(_maxid, "");
0645   std::copy(
0646     std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
0647     std::sregex_token_iterator(), _result.begin());
0648   signal_set_t _sigset{};
0649   for(auto& itr : _result)
0650     _add_signal(itr, _sigset);
0651   return Enable(_sigset);
0652 }
0653 
0654 //----------------------------------------------------------------------------//
0655 
0656 inline G4int G4Backtrace::Disable(signal_set_t _signals)
0657 {
0658   if(_signals.empty())
0659   {
0660     for(auto& itr : GetData().is_active)
0661       _signals.insert(itr.first);
0662   }
0663 
0664   G4int cnt = 0;
0665   for(auto& itr : _signals)
0666   {
0667     if(itr < 0)
0668       continue;
0669     if(!GetData().is_active[itr])
0670       continue;
0671     ++cnt;
0672     sigaction(itr, &(GetData().previous[itr]), nullptr);
0673     GetData().current.erase(itr);
0674     GetData().is_active[itr] = false;
0675   }
0676   return cnt;
0677 }
0678 
0679 //----------------------------------------------------------------------------//
0680 
0681 inline G4int G4Backtrace::GetSignal(const std::string& sid)
0682 {
0683   for(auto&& itr : GetData().identifiers)
0684   {
0685     if(std::get<0>(itr) == sid)
0686       return std::get<1>(itr);
0687   }
0688   return -1;
0689 }
0690 
0691 //----------------------------------------------------------------------------//
0692 
0693 inline std::string G4Backtrace::Description(G4int sig)
0694 {
0695   for(auto&& itr : GetData().identifiers)
0696   {
0697     if(std::get<1>(itr) == sig)
0698     {
0699       std::stringstream ss;
0700       ss << " signal = " << std::setw(8) << std::get<0>(itr)
0701          << ", value = " << std::setw(4) << std::get<1>(itr)
0702          << ", description = " << std::get<2>(itr);
0703       return ss.str();
0704     }
0705   }
0706   std::stringstream ss;
0707   ss << " signal = " << std::setw(8) << "unknown"
0708      << ", value = " << std::setw(4) << sig;
0709   return ss.str();
0710 }
0711 
0712 //----------------------------------------------------------------------------//
0713 
0714 #else
0715 
0716 #  include <array>
0717 #  include <functional>
0718 #  include <map>
0719 #  include <set>
0720 #  include <string>
0721 #  include <tuple>
0722 #  include <vector>
0723 
0724 // dummy implementation
0725 class G4Backtrace
0726 {
0727  public:
0728   struct fake_siginfo
0729   {};
0730   struct fake_sigaction
0731   {};
0732 
0733   using siginfo_t = fake_siginfo;
0734   using sigaction_t = fake_sigaction;
0735   using exit_action_t = std::function<void(G4int)>;
0736   using frame_func_t = std::function<G4String(const char*)>;
0737   using signal_set_t = std::set<G4int>;
0738 
0739  public:
0740   struct actions
0741   {
0742     using id_entry_t = std::tuple<std::string, G4int, std::string>;
0743     using id_list_t = std::vector<id_entry_t>;
0744 
0745     std::map<G4int, G4bool> is_active = {};
0746     std::map<G4int, sigaction_t> current = {};
0747     std::map<G4int, sigaction_t> previous = {};
0748     std::vector<exit_action_t> exit_actions = {};
0749     const id_list_t identifiers = {};
0750   };
0751 
0752  public:
0753   static void Handler(G4int, siginfo_t*, void*) {}
0754   static void Message(G4int, siginfo_t*, std::ostream&) {}
0755   static void ExitAction(G4int) {}
0756   static G4int Enable(const std::string&) { return 0; }
0757   static G4int Enable(const signal_set_t& = DefaultSignals()) { return 0; }
0758   static G4int Disable(signal_set_t = {}) { return 0; }
0759   static G4int GetSignal(const std::string&) { return -1; }
0760   static std::string Description(G4int) { return std::string{}; }
0761 
0762   template <typename FuncT>
0763   static void AddExitAction(FuncT&&)
0764   {}
0765 
0766   template <std::size_t Depth, std::size_t Offset = 0, typename FuncT = frame_func_t>
0767   static std::array<G4ResultOf_t<FuncT, const char*>, Depth> GetMangled(
0768     FuncT&& func = FrameFunctor())
0769   {
0770     using type = G4ResultOf_t<FuncT, const char*>;
0771     auto ret = std::array<type, Depth>{};
0772     ret.fill(func(""));
0773     return ret;
0774   }
0775 
0776   template <std::size_t Depth, std::size_t Offset = 0, typename FuncT = frame_func_t>
0777   static std::array<G4ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
0778     FuncT&& func = FrameFunctor())
0779   {
0780     using type = G4ResultOf_t<FuncT, const char*>;
0781     auto ret = std::array<type, Depth>{};
0782     ret.fill(func(""));
0783     return ret;
0784   }
0785 
0786   // a functor called for each frame in the backtrace
0787   static frame_func_t& FrameFunctor()
0788   {
0789     static frame_func_t _instance = [](const char* _s) { return G4String(_s); };
0790     return _instance;
0791   }
0792 
0793   // default set of signals
0794   static signal_set_t& DefaultSignals()
0795   {
0796     static signal_set_t _instance = {};
0797     return _instance;
0798   }
0799 
0800   static actions& GetData()
0801   {
0802     static auto _instance = actions{};
0803     return _instance;
0804   }
0805 };
0806 
0807 //----------------------------------------------------------------------------//
0808 
0809 #endif  // G4SIGNAL_AVAILABLE
0810 #endif  // G4Backtrace_hh