Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/global/management/include/G4Backtrace.hh

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /global/management/include/G4Backtrace.hh (Version 11.3.0) and /global/management/include/G4Backtrace.hh (Version 10.7.p1)


  1 //                                                  1 //
  2 // *******************************************      2 // ********************************************************************
  3 // * License and Disclaimer                         3 // * License and Disclaimer                                           *
  4 // *                                                4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of th      5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided      6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License      7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/      8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.           9 // * include a list of copyright holders.                             *
 10 // *                                               10 // *                                                                  *
 11 // * Neither the authors of this software syst     11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing fin     12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warran     13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assum     14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file      15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitatio     16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                               17 // *                                                                  *
 18 // * This  code  implementation is the result      18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboratio     19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distri     20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  ag     21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publicati     22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Sof     23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // *******************************************     24 // ********************************************************************
 25 //                                                 25 //
 26 // G4Backtrace                                     26 // G4Backtrace
 27 //                                                 27 //
 28 // Description:                                    28 // Description:
 29 //                                                 29 //
 30 //  Prints backtraces after signals are caught     30 //  Prints backtraces after signals are caught. Available on Unix.
 31 //                                                 31 //
 32 // Usage:                                          32 // Usage:
 33 //  A standard set of signals are enabled by d     33 //  A standard set of signals are enabled by default:
 34 //                                                 34 //
 35 //     SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGB     35 //     SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
 36 //                                                 36 //
 37 //  These should not interfere with debuggers      37 //  These should not interfere with debuggers and/or G4FPEDetection.
 38 //  In order to turn off handling for one or m     38 //  In order to turn off handling for one or more signals, one can do:
 39 //                                                 39 //
 40 //    G4Backtrace::DefaultSignals() = std::set <<  40 //    G4BackTrace::DefaultSignals() = std::set<int>{};
 41 //    G4Backtrace::DefaultSignals() = std::set <<  41 //    G4BackTrace::DefaultSignals() = std::set<int>{ SIGSEGV };
 42 //                                                 42 //
 43 //  and so on, *before* creating the run-manag     43 //  and so on, *before* creating the run-manager. After the run-manager
 44 //  has been created, one should disable the s     44 //  has been created, one should disable the signals:
 45 //                                                 45 //
 46 //    G4Backtrace::Disable(G4Backtrace::Defaul <<  46 //    G4BackTrace::Disable(G4BackTrace::DefaultSignals());
 47 //                                                 47 //
 48 //  Additionally, at runtime, the environment      48 //  Additionally, at runtime, the environment variable "G4BACKTRACE" can
 49 //  be set to select a specific set of signals     49 //  be set to select a specific set of signals or none, e.g. in bash:
 50 //                                                 50 //
 51 //    export G4BACKTRACE="SIGQUIT,SIGSEGV"         51 //    export G4BACKTRACE="SIGQUIT,SIGSEGV"
 52 //    export G4BACKTRACE="none"                    52 //    export G4BACKTRACE="none"
 53 //                                                 53 //
 54 //  The environment variable is case-insensiti     54 //  The environment variable is case-insensitive and can use any of the
 55 //  following delimiters: space, comma, semi-c     55 //  following delimiters: space, comma, semi-colon, colon
 56 //                                                 56 //
 57 // Author: J.Madsen, 19 October 2020               57 // Author: J.Madsen, 19 October 2020
 58 // -------------------------------------------     58 // --------------------------------------------------------------------
 59                                                    59 
 60 #ifndef G4Backtrace_hh                             60 #ifndef G4Backtrace_hh
 61 #define G4Backtrace_hh 1                           61 #define G4Backtrace_hh 1
 62                                                    62 
 63 #include "G4Types.hh"                              63 #include "G4Types.hh"
 64 #include "G4String.hh"                             64 #include "G4String.hh"
 65 #include "G4Threading.hh"                          65 #include "G4Threading.hh"
 66                                                    66 
 67 #if defined(__APPLE__) || defined(__MACH__)        67 #if defined(__APPLE__) || defined(__MACH__)
 68 #  if !defined(G4MACOS)                            68 #  if !defined(G4MACOS)
 69 #    define G4MACOS                                69 #    define G4MACOS
 70 #  endif                                           70 #  endif
 71 #  if !defined(G4UNIX)                             71 #  if !defined(G4UNIX)
 72 #    define G4UNIX                                 72 #    define G4UNIX
 73 #  endif                                           73 #  endif
 74 #elif defined(__linux__) || defined(__linux) |     74 #elif defined(__linux__) || defined(__linux) || defined(linux) ||              \
 75   defined(__gnu_linux__)                           75   defined(__gnu_linux__)
 76 #  if !defined(G4LINUX)                            76 #  if !defined(G4LINUX)
 77 #    define G4LINUX                                77 #    define G4LINUX
 78 #  endif                                           78 #  endif
 79 #  if !defined(G4UNIX)                             79 #  if !defined(G4UNIX)
 80 #    define G4UNIX                                 80 #    define G4UNIX
 81 #  endif                                           81 #  endif
 82 #elif defined(__unix__) || defined(__unix) ||      82 #elif defined(__unix__) || defined(__unix) || defined(unix)
 83 #  if !defined(G4UNIX)                             83 #  if !defined(G4UNIX)
 84 #    define G4UNIX                                 84 #    define G4UNIX
 85 #  endif                                           85 #  endif
 86 #endif                                             86 #endif
 87                                                    87 
 88 #if defined(G4UNIX) && !defined(WIN32)         <<  88 #if defined(G4UNIX)
 89 #  include <cxxabi.h>                              89 #  include <cxxabi.h>
 90 #  include <execinfo.h>                            90 #  include <execinfo.h>
 91 #  include <unistd.h>                              91 #  include <unistd.h>
 92 #endif                                             92 #endif
 93                                                    93 
 94 #if defined(G4LINUX)                               94 #if defined(G4LINUX)
 95 #  include <features.h>                            95 #  include <features.h>
 96 #endif                                             96 #endif
 97                                                    97 
 98 #include <cfenv>                                   98 #include <cfenv>
 99 #include <csignal>                                 99 #include <csignal>
100 #include <type_traits>                            100 #include <type_traits>
101                                                   101 
102 template <typename FuncT, typename... ArgTypes << 102 template <typename FuncT>
103 using G4ResultOf_t = std::invoke_result_t<Func << 103 using G4ResultOf_t = typename std::result_of<FuncT>::type;
104                                                   104 
105 // compatible OS and compiler                     105 // compatible OS and compiler
106 #if defined(G4UNIX) &&                            106 #if defined(G4UNIX) &&                                                         \
107   (defined(__GNUC__) || defined(__clang__) ||     107   (defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER))
108 #  if !defined(G4SIGNAL_AVAILABLE)                108 #  if !defined(G4SIGNAL_AVAILABLE)
109 #    define G4SIGNAL_AVAILABLE                    109 #    define G4SIGNAL_AVAILABLE
110 #  endif                                          110 #  endif
111 #  if !defined(G4DEMANGLE_AVAILABLE)              111 #  if !defined(G4DEMANGLE_AVAILABLE)
112 #    define G4DEMANGLE_AVAILABLE                  112 #    define G4DEMANGLE_AVAILABLE
113 #  endif                                          113 #  endif
114 #endif                                            114 #endif
115                                                   115 
116 #if !defined(G4PSIGINFO_AVAILABLE)                116 #if !defined(G4PSIGINFO_AVAILABLE)
117 #  if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE     117 #  if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
118 #    define G4PSIGINFO_AVAILABLE 1                118 #    define G4PSIGINFO_AVAILABLE 1
119 #  else                                           119 #  else
120 #    define G4PSIGINFO_AVAILABLE 0                120 #    define G4PSIGINFO_AVAILABLE 0
121 #  endif                                          121 #  endif
122 #endif                                            122 #endif
123                                                   123 
124 //--------------------------------------------    124 //----------------------------------------------------------------------------//
125                                                   125 
126 inline G4String G4Demangle(const char* _str)      126 inline G4String G4Demangle(const char* _str)
127 {                                                 127 {
128 #if defined(G4DEMANGLE_AVAILABLE)                 128 #if defined(G4DEMANGLE_AVAILABLE)
129   // demangling a string when delimiting          129   // demangling a string when delimiting
130   G4int _status = 0;                           << 130   int _status = 0;
131   char* _ret  = ::abi::__cxa_demangle(_str, nu    131   char* _ret  = ::abi::__cxa_demangle(_str, nullptr, nullptr, &_status);
132   if((_ret != nullptr) && _status == 0)        << 132   if(_ret && _status == 0)
133     return G4String(const_cast<const char*>(_r    133     return G4String(const_cast<const char*>(_ret));
134   return _str;                                    134   return _str;
135 #else                                             135 #else
136   return _str;                                    136   return _str;
137 #endif                                            137 #endif
138 }                                                 138 }
139                                                   139 
140 //--------------------------------------------    140 //----------------------------------------------------------------------------//
141                                                   141 
142 inline G4String G4Demangle(const G4String& _st    142 inline G4String G4Demangle(const G4String& _str)
143 {                                                 143 {
144   return G4Demangle(_str.c_str());                144   return G4Demangle(_str.c_str());
145 }                                                 145 }
146                                                   146 
147 //--------------------------------------------    147 //----------------------------------------------------------------------------//
148                                                   148 
149 template <typename Tp>                            149 template <typename Tp>
150 inline G4String G4Demangle()                      150 inline G4String G4Demangle()
151 {                                                 151 {
152   return G4Demangle(typeid(Tp).name());           152   return G4Demangle(typeid(Tp).name());
153 }                                                 153 }
154                                                   154 
155 //--------------------------------------------    155 //----------------------------------------------------------------------------//
156 //                                                156 //
157 //      ONLY IF G4SIGNAL_AVAILABLE                157 //      ONLY IF G4SIGNAL_AVAILABLE
158 //                                                158 //
159 //--------------------------------------------    159 //----------------------------------------------------------------------------//
160 //                                                160 //
161 #if defined(G4SIGNAL_AVAILABLE)                   161 #if defined(G4SIGNAL_AVAILABLE)
162 //                                                162 //
163 //  these are not in the original POSIX.1-1990    163 //  these are not in the original POSIX.1-1990 standard so we are defining
164 //  them in case the OS hasn't                    164 //  them in case the OS hasn't
165 //  POSIX-1.2001                                  165 //  POSIX-1.2001
166 #  ifndef SIGTRAP                                 166 #  ifndef SIGTRAP
167 #    define SIGTRAP 5                             167 #    define SIGTRAP 5
168 #  endif                                          168 #  endif
169 //  not specified in POSIX.1-2001, but neverth    169 //  not specified in POSIX.1-2001, but nevertheless appears on most other
170 //  UNIX systems, where its default action is     170 //  UNIX systems, where its default action is typically to terminate the
171 //  process with a core dump.                     171 //  process with a core dump.
172 #  ifndef SIGEMT                                  172 #  ifndef SIGEMT
173 #    define SIGEMT 7                              173 #    define SIGEMT 7
174 #  endif                                          174 #  endif
175 //  POSIX-1.2001                                  175 //  POSIX-1.2001
176 #  ifndef SIGURG                                  176 #  ifndef SIGURG
177 #    define SIGURG 16                             177 #    define SIGURG 16
178 #  endif                                          178 #  endif
179 //  POSIX-1.2001                                  179 //  POSIX-1.2001
180 #  ifndef SIGXCPU                                 180 #  ifndef SIGXCPU
181 #    define SIGXCPU 24                            181 #    define SIGXCPU 24
182 #  endif                                          182 #  endif
183 //  POSIX-1.2001                                  183 //  POSIX-1.2001
184 #  ifndef SIGXFSZ                                 184 #  ifndef SIGXFSZ
185 #    define SIGXFSZ 25                            185 #    define SIGXFSZ 25
186 #  endif                                          186 #  endif
187 //  POSIX-1.2001                                  187 //  POSIX-1.2001
188 #  ifndef SIGVTALRM                               188 #  ifndef SIGVTALRM
189 #    define SIGVTALRM 26                          189 #    define SIGVTALRM 26
190 #  endif                                          190 #  endif
191 //  POSIX-1.2001                                  191 //  POSIX-1.2001
192 #  ifndef SIGPROF                                 192 #  ifndef SIGPROF
193 #    define SIGPROF 27                            193 #    define SIGPROF 27
194 #  endif                                          194 #  endif
195 //  POSIX-1.2001                                  195 //  POSIX-1.2001
196 #  ifndef SIGINFO                                 196 #  ifndef SIGINFO
197 #    define SIGINFO 29                            197 #    define SIGINFO 29
198 #  endif                                          198 #  endif
199                                                   199 
200 //--------------------------------------------    200 //----------------------------------------------------------------------------//
201                                                   201 
202 #  include <algorithm>                            202 #  include <algorithm>
203 #  include <array>                                203 #  include <array>
204 #  include <cstdlib>                              204 #  include <cstdlib>
205 #  include <cstdio>                            << 
206 #  include <functional>                           205 #  include <functional>
207 #  include <iomanip>                              206 #  include <iomanip>
208 #  include <iostream>                             207 #  include <iostream>
209 #  include <map>                                  208 #  include <map>
                                                   >> 209 #  include <mutex>
210 #  include <regex>                                210 #  include <regex>
211 #  include <set>                                  211 #  include <set>
212 #  include <sstream>                              212 #  include <sstream>
213 #  include <string>                               213 #  include <string>
214 #  include <tuple>                                214 #  include <tuple>
215 #  include <vector>                               215 #  include <vector>
216                                                   216 
217 //--------------------------------------------    217 //----------------------------------------------------------------------------//
218                                                   218 
219 class G4Backtrace                                 219 class G4Backtrace
220 {                                                 220 {
221  public:                                          221  public:
222   using sigaction_t   = struct sigaction;         222   using sigaction_t   = struct sigaction;
223   using exit_action_t = std::function<void(G4i << 223   using exit_action_t = std::function<void(int)>;
224   using frame_func_t  = std::function<G4String    224   using frame_func_t  = std::function<G4String(const char*)>;
225   using signal_set_t  = std::set<G4int>;       << 225   using signal_set_t  = std::set<int>;
226                                                   226 
227  public:                                          227  public:
228   struct actions                                  228   struct actions
229   {                                               229   {
230     using id_entry_t = std::tuple<std::string, << 230     using id_entry_t = std::tuple<std::string, int, std::string>;
231     using id_list_t  = std::vector<id_entry_t>    231     using id_list_t  = std::vector<id_entry_t>;
232                                                   232 
233     std::map<G4int, G4bool> is_active          << 233     std::shared_ptr<std::mutex> lock        = std::make_shared<std::mutex>();
234     std::map<G4int, sigaction_t> current       << 234     std::map<int, bool> is_active           = {};
235     std::map<G4int, sigaction_t> previous      << 235     std::map<int, sigaction_t> current      = {};
                                                   >> 236     std::map<int, sigaction_t> previous     = {};
236     std::vector<exit_action_t> exit_actions =     237     std::vector<exit_action_t> exit_actions = {};
237     const id_list_t identifiers             =     238     const id_list_t identifiers             = {
238       id_entry_t("SIGHUP", SIGHUP, "terminal l    239       id_entry_t("SIGHUP", SIGHUP, "terminal line hangup"),
239       id_entry_t("SIGINT", SIGINT, "interrupt     240       id_entry_t("SIGINT", SIGINT, "interrupt program"),
240       id_entry_t("SIGQUIT", SIGQUIT, "quit pro    241       id_entry_t("SIGQUIT", SIGQUIT, "quit program"),
241       id_entry_t("SIGILL", SIGILL, "illegal in    242       id_entry_t("SIGILL", SIGILL, "illegal instruction"),
242       id_entry_t("SIGTRAP", SIGTRAP, "trace tr    243       id_entry_t("SIGTRAP", SIGTRAP, "trace trap"),
243       id_entry_t("SIGABRT", SIGABRT, "abort pr    244       id_entry_t("SIGABRT", SIGABRT, "abort program (formerly SIGIOT)"),
244       id_entry_t("SIGEMT", SIGEMT, "emulate in    245       id_entry_t("SIGEMT", SIGEMT, "emulate instruction executed"),
245       id_entry_t("SIGFPE", SIGFPE, "floating-p    246       id_entry_t("SIGFPE", SIGFPE, "floating-point exception"),
246       id_entry_t("SIGKILL", SIGKILL, "kill pro    247       id_entry_t("SIGKILL", SIGKILL, "kill program"),
247       id_entry_t("SIGBUS", SIGBUS, "bus error"    248       id_entry_t("SIGBUS", SIGBUS, "bus error"),
248       id_entry_t("SIGSEGV", SIGSEGV, "segmenta    249       id_entry_t("SIGSEGV", SIGSEGV, "segmentation violation"),
249       id_entry_t("SIGSYS", SIGSYS, "non-existe    250       id_entry_t("SIGSYS", SIGSYS, "non-existent system call invoked"),
250       id_entry_t("SIGPIPE", SIGPIPE, "write on    251       id_entry_t("SIGPIPE", SIGPIPE, "write on a pipe with no reader"),
251       id_entry_t("SIGALRM", SIGALRM, "real-tim    252       id_entry_t("SIGALRM", SIGALRM, "real-time timer expired"),
252       id_entry_t("SIGTERM", SIGTERM, "software    253       id_entry_t("SIGTERM", SIGTERM, "software termination signal"),
253       id_entry_t("SIGURG", SIGURG, "urgent con    254       id_entry_t("SIGURG", SIGURG, "urgent condition present on socket"),
254       id_entry_t("SIGSTOP", SIGSTOP, "stop (ca    255       id_entry_t("SIGSTOP", SIGSTOP, "stop (cannot be caught or ignored)"),
255       id_entry_t("SIGTSTP", SIGTSTP, "stop sig    256       id_entry_t("SIGTSTP", SIGTSTP, "stop signal generated from keyboard"),
256       id_entry_t("SIGCONT", SIGCONT, "continue    257       id_entry_t("SIGCONT", SIGCONT, "continue after stop"),
257       id_entry_t("SIGCHLD", SIGCHLD, "child st    258       id_entry_t("SIGCHLD", SIGCHLD, "child status has changed"),
258       id_entry_t("SIGTTIN", SIGTTIN,              259       id_entry_t("SIGTTIN", SIGTTIN,
259                  "background read attempted fr    260                  "background read attempted from control terminal"),
260       id_entry_t("SIGTTOU", SIGTTOU,              261       id_entry_t("SIGTTOU", SIGTTOU,
261                  "background write attempted t    262                  "background write attempted to control terminal"),
262       id_entry_t("SIGIO ", SIGIO, "I/O is poss    263       id_entry_t("SIGIO ", SIGIO, "I/O is possible on a descriptor"),
263       id_entry_t("SIGXCPU", SIGXCPU, "cpu time    264       id_entry_t("SIGXCPU", SIGXCPU, "cpu time limit exceeded"),
264       id_entry_t("SIGXFSZ", SIGXFSZ, "file siz    265       id_entry_t("SIGXFSZ", SIGXFSZ, "file size limit exceeded"),
265       id_entry_t("SIGVTALRM", SIGVTALRM, "virt    266       id_entry_t("SIGVTALRM", SIGVTALRM, "virtual time alarm"),
266       id_entry_t("SIGPROF", SIGPROF, "profilin    267       id_entry_t("SIGPROF", SIGPROF, "profiling timer alarm"),
267       id_entry_t("SIGWINCH", SIGWINCH, "Window    268       id_entry_t("SIGWINCH", SIGWINCH, "Window size change"),
268       id_entry_t("SIGINFO", SIGINFO, "status r    269       id_entry_t("SIGINFO", SIGINFO, "status request from keyboard"),
269       id_entry_t("SIGUSR1", SIGUSR1, "User def    270       id_entry_t("SIGUSR1", SIGUSR1, "User defined signal 1"),
270       id_entry_t("SIGUSR2", SIGUSR2, "User def    271       id_entry_t("SIGUSR2", SIGUSR2, "User defined signal 2")
271     };                                            272     };
272   };                                              273   };
273                                                   274 
274  public:                                          275  public:
275   // a functor called for each frame in the ba    276   // a functor called for each frame in the backtrace
276   static frame_func_t& FrameFunctor();            277   static frame_func_t& FrameFunctor();
277   // default set of signals                       278   // default set of signals
278   static signal_set_t& DefaultSignals();          279   static signal_set_t& DefaultSignals();
279   // the signal handler                           280   // the signal handler
280   static void Handler(G4int sig, siginfo_t* si << 281   static void Handler(int sig, siginfo_t* sinfo, void* context);
281   // information message about the signal, per    282   // information message about the signal, performs exit-actions
282   // and prints back-trace                        283   // and prints back-trace
283   static void Message(G4int sig, siginfo_t* si << 284   static void Message(int sig, siginfo_t* sinfo, std::ostream&);
284   // calls user-provided functions after signa    285   // calls user-provided functions after signal is caught but before abort
285   static void ExitAction(G4int sig);           << 286   static void ExitAction(int sig);
286   // enable signals via a string (which is tok    287   // enable signals via a string (which is tokenized)
287   static G4int Enable(const std::string&);     << 288   static int Enable(const std::string&);
288   // enable signals via set of integers, anyth    289   // enable signals via set of integers, anything less than zero is ignored
289   static G4int Enable(const signal_set_t& _sig << 290   static int Enable(const signal_set_t& _signals = DefaultSignals());
290   // disable signals                              291   // disable signals
291   static G4int Disable(signal_set_t _signals = << 292   static int Disable(signal_set_t _signals = {});
292   // gets the numeric value for a signal name     293   // gets the numeric value for a signal name
293   static G4int GetSignal(const std::string&);  << 294   static int GetSignal(const std::string&);
294   // provides a description of the signal         295   // provides a description of the signal
295   static std::string Description(G4int sig);   << 296   static std::string Description(int sig);
296                                                   297 
297   // adds an exit action                          298   // adds an exit action
298   template <typename FuncT>                       299   template <typename FuncT>
299   static void AddExitAction(FuncT&& func);        300   static void AddExitAction(FuncT&& func);
300                                                   301 
301   // gets a backtrace of "Depth" frames. The o    302   // gets a backtrace of "Depth" frames. The offset parameter is used
302   // to ignore initial frames (such as this fu    303   // to ignore initial frames (such as this function). A callback
303   // can be provided to inspect and/or tweak t    304   // can be provided to inspect and/or tweak the frame string
304   template <std::size_t Depth, std::size_t Off << 305   template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
305   static std::array<G4ResultOf_t<FuncT, const  << 306   static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetMangled(
306     FuncT&& func = FrameFunctor());               307     FuncT&& func = FrameFunctor());
307                                                   308 
308   // gets a demangled backtrace of "Depth" fra    309   // gets a demangled backtrace of "Depth" frames. The offset parameter is
309   // used to ignore initial frames (such as th    310   // used to ignore initial frames (such as this function). A callback
310   // can be provided to inspect and/or tweak t    311   // can be provided to inspect and/or tweak the frame string
311   template <std::size_t Depth, std::size_t Off << 312   template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
312   static std::array<G4ResultOf_t<FuncT, const  << 313   static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetDemangled(
313     FuncT&& func = FrameFunctor());               314     FuncT&& func = FrameFunctor());
314                                                   315 
315  private:                                         316  private:
316   static actions& GetData()                       317   static actions& GetData()
317   {                                               318   {
318     static auto _instance = actions{};            319     static auto _instance = actions{};
319     return _instance;                             320     return _instance;
320   }                                               321   }
321 };                                                322 };
322                                                   323 
323 //--------------------------------------------    324 //----------------------------------------------------------------------------//
324                                                   325 
325 // a functor called for each frame in the back    326 // a functor called for each frame in the backtrace
326 inline G4Backtrace::frame_func_t& G4Backtrace:    327 inline G4Backtrace::frame_func_t& G4Backtrace::FrameFunctor()
327 {                                                 328 {
328   static frame_func_t _instance = [](const cha    329   static frame_func_t _instance = [](const char* inp) { return G4String(inp); };
329   return _instance;                               330   return _instance;
330 }                                                 331 }
331                                                   332 
332 //--------------------------------------------    333 //----------------------------------------------------------------------------//
333                                                   334 
334 // default set of signals                         335 // default set of signals
335 inline G4Backtrace::signal_set_t& G4Backtrace:    336 inline G4Backtrace::signal_set_t& G4Backtrace::DefaultSignals()
336 {                                                 337 {
337   static signal_set_t _instance = { SIGQUIT, S    338   static signal_set_t _instance = { SIGQUIT, SIGILL, SIGABRT,
338                                     SIGKILL, S    339                                     SIGKILL, SIGBUS, SIGSEGV };
339   return _instance;                               340   return _instance;
340 }                                                 341 }
341                                                   342 
342 //--------------------------------------------    343 //----------------------------------------------------------------------------//
343                                                   344 
344 template <typename FuncT>                         345 template <typename FuncT>
345 inline void G4Backtrace::AddExitAction(FuncT&&    346 inline void G4Backtrace::AddExitAction(FuncT&& func)
346 {                                                 347 {
347   GetData().exit_actions.emplace_back(std::for    348   GetData().exit_actions.emplace_back(std::forward<FuncT>(func));
348 }                                                 349 }
349                                                   350 
350 //--------------------------------------------    351 //----------------------------------------------------------------------------//
351                                                   352 
352 inline void G4Backtrace::ExitAction(G4int sig) << 353 inline void G4Backtrace::ExitAction(int sig)
353 {                                                 354 {
354   for(auto& itr : GetData().exit_actions)         355   for(auto& itr : GetData().exit_actions)
355     itr(sig);                                     356     itr(sig);
356 }                                                 357 }
357                                                   358 
358 //--------------------------------------------    359 //----------------------------------------------------------------------------//
359                                                   360 
360 template <std::size_t Depth, std::size_t Offse << 361 template <size_t Depth, size_t Offset, typename FuncT>
361 inline std::array<G4ResultOf_t<FuncT, const ch << 362 inline std::array<G4ResultOf_t<FuncT(const char*)>, Depth>
362 G4Backtrace::GetMangled(FuncT&& func)             363 G4Backtrace::GetMangled(FuncT&& func)
363 {                                                 364 {
364   static_assert((Depth - Offset) >= 1, "Error     365   static_assert((Depth - Offset) >= 1, "Error Depth - Offset should be >= 1");
365                                                   366 
366   using type = G4ResultOf_t<FuncT, const char* << 367   using type = G4ResultOf_t<FuncT(const char*)>;
367   // destination                                  368   // destination
368   std::array<type, Depth> btrace;                 369   std::array<type, Depth> btrace;
369   btrace.fill((std::is_pointer<type>::value) ?    370   btrace.fill((std::is_pointer<type>::value) ? nullptr : type{});
370                                                   371 
371   // plus one for this stack-frame                372   // plus one for this stack-frame
372   std::array<void*, Depth + Offset> buffer;       373   std::array<void*, Depth + Offset> buffer;
373   // size of returned buffer                      374   // size of returned buffer
374   auto sz = backtrace(buffer.data(), Depth + O    375   auto sz = backtrace(buffer.data(), Depth + Offset);
375   // size of relevant data                        376   // size of relevant data
376   auto n = sz - Offset;                           377   auto n = sz - Offset;
377                                                   378 
378   // skip ahead (Offset + 1) stack frames         379   // skip ahead (Offset + 1) stack frames
379   char** bsym = backtrace_symbols(buffer.data( << 380   char** bsym = backtrace_symbols(buffer.data() + Offset, n);
380                                                   381 
381   // report errors                                382   // report errors
382   if(bsym == nullptr)                             383   if(bsym == nullptr)
383     perror("backtrace_symbols");                  384     perror("backtrace_symbols");
384   else                                            385   else
385   {                                               386   {
386     for(decltype(n) i = 0; i < n; ++i)            387     for(decltype(n) i = 0; i < n; ++i)
387       btrace[i] = func(bsym[i]);                  388       btrace[i] = func(bsym[i]);
388     free(bsym);                                   389     free(bsym);
389   }                                               390   }
390   return btrace;                                  391   return btrace;
391 }                                                 392 }
392                                                   393 
393 //--------------------------------------------    394 //----------------------------------------------------------------------------//
394                                                   395 
395 template <std::size_t Depth, std::size_t Offse << 396 template <size_t Depth, size_t Offset, typename FuncT>
396 inline std::array<G4ResultOf_t<FuncT, const ch << 397 inline std::array<G4ResultOf_t<FuncT(const char*)>, Depth>
397 G4Backtrace::GetDemangled(FuncT&& func)           398 G4Backtrace::GetDemangled(FuncT&& func)
398 {                                                 399 {
399   auto demangle_bt = [&](const char* cstr) {      400   auto demangle_bt = [&](const char* cstr) {
400     auto _trim = [](std::string& _sub, std::si << 401     auto _trim = [](std::string& _sub, size_t& _len) {
401       std::size_t _pos = 0;                    << 402       size_t _pos = 0;
402       while((_pos = _sub.find_first_of(' ')) =    403       while((_pos = _sub.find_first_of(' ')) == 0)
403       {                                           404       {
404         _sub = _sub.erase(_pos, 1);               405         _sub = _sub.erase(_pos, 1);
405         --_len;                                   406         --_len;
406       }                                           407       }
407       while((_pos = _sub.find_last_of(' ')) ==    408       while((_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
408       {                                           409       {
409         _sub = _sub.substr(0, _sub.length() -     410         _sub = _sub.substr(0, _sub.length() - 1);
410         --_len;                                   411         --_len;
411       }                                           412       }
412       return _sub;                                413       return _sub;
413     };                                            414     };
414                                                   415 
415     auto str = G4Demangle(std::string(cstr));     416     auto str = G4Demangle(std::string(cstr));
416     auto beg = str.find('(');                  << 417     auto beg = str.find("(");
417     if(beg == std::string::npos)                  418     if(beg == std::string::npos)
418     {                                             419     {
419       beg = str.find("_Z");                       420       beg = str.find("_Z");
420       if(beg != std::string::npos)                421       if(beg != std::string::npos)
421         beg -= 1;                                 422         beg -= 1;
422     }                                             423     }
423     auto end = str.find('+', beg);             << 424     auto end = str.find("+", beg);
424     if(beg != std::string::npos && end != std:    425     if(beg != std::string::npos && end != std::string::npos)
425     {                                             426     {
426       auto len = end - (beg + 1);                 427       auto len = end - (beg + 1);
427       auto sub = str.substr(beg + 1, len);        428       auto sub = str.substr(beg + 1, len);
428       auto dem = G4Demangle(_trim(sub, len));     429       auto dem = G4Demangle(_trim(sub, len));
429       str      = str.replace(beg + 1, len, dem    430       str      = str.replace(beg + 1, len, dem);
430     }                                             431     }
431     else if(beg != std::string::npos)             432     else if(beg != std::string::npos)
432     {                                             433     {
433       auto len = str.length() - (beg + 1);        434       auto len = str.length() - (beg + 1);
434       auto sub = str.substr(beg + 1, len);        435       auto sub = str.substr(beg + 1, len);
435       auto dem = G4Demangle(_trim(sub, len));     436       auto dem = G4Demangle(_trim(sub, len));
436       str      = str.replace(beg + 1, len, dem    437       str      = str.replace(beg + 1, len, dem);
437     }                                             438     }
438     else if(end != std::string::npos)             439     else if(end != std::string::npos)
439     {                                             440     {
440       auto len = end;                             441       auto len = end;
441       auto sub = str.substr(beg, len);            442       auto sub = str.substr(beg, len);
442       auto dem = G4Demangle(_trim(sub, len));     443       auto dem = G4Demangle(_trim(sub, len));
443       str      = str.replace(beg, len, dem);      444       str      = str.replace(beg, len, dem);
444     }                                             445     }
445     return func(str.c_str());                     446     return func(str.c_str());
446   };                                              447   };
447   return GetMangled<Depth, Offset>(demangle_bt    448   return GetMangled<Depth, Offset>(demangle_bt);
448 }                                                 449 }
449                                                   450 
450 //--------------------------------------------    451 //----------------------------------------------------------------------------//
451                                                   452 
452 inline void G4Backtrace::Message(G4int sig, si << 453 inline void G4Backtrace::Message(int sig, siginfo_t* sinfo, std::ostream& os)
453 {                                                 454 {
454   // try to avoid as many dynamic allocations  << 455   std::stringstream message;
455   // overflowing the signal stack              << 456   message << "\n### CAUGHT SIGNAL: " << sig << " ### ";
456                                                << 457   if(sinfo)
457   // ignore future signals of this type        << 458     message << "address: " << sinfo->si_addr << ", ";
458   signal(sig, SIG_IGN);                        << 459   message << Description(sig) << ". ";
459                                                << 
460   os << "\n### CAUGHT SIGNAL: " << sig << " ## << 
461   if(sinfo != nullptr)                         << 
462     os << "address: " << sinfo->si_addr << ",  << 
463   os << Description(sig) << ". ";              << 
464                                                   460 
465   if(sig == SIGSEGV)                              461   if(sig == SIGSEGV)
466   {                                               462   {
467     if(sinfo != nullptr)                       << 463     if(sinfo)
468     {                                             464     {
469       switch(sinfo->si_code)                      465       switch(sinfo->si_code)
470       {                                           466       {
471         case SEGV_MAPERR:                         467         case SEGV_MAPERR:
472           os << "Address not mapped to object. << 468           message << "Address not mapped to object.";
473           break;                                  469           break;
474         case SEGV_ACCERR:                         470         case SEGV_ACCERR:
475           os << "Invalid permissions for mappe << 471           message << "Invalid permissions for mapped object.";
476           break;                                  472           break;
477         default:                                  473         default:
478           os << "Unknown segmentation fault er << 474           message << "Unknown segmentation fault error: " << sinfo->si_code
                                                   >> 475                   << ".";
479           break;                                  476           break;
480       }                                           477       }
481     }                                             478     }
482     else                                          479     else
483     {                                             480     {
484       os << "Segmentation fault (unknown).";   << 481       message << "Segmentation fault (unknown).";
485     }                                             482     }
486   }                                               483   }
487   else if(sig == SIGFPE)                          484   else if(sig == SIGFPE)
488   {                                               485   {
489     if(sinfo != nullptr)                       << 486     if(sinfo)
490     {                                             487     {
491       switch(sinfo->si_code)                      488       switch(sinfo->si_code)
492       {                                           489       {
493         case FE_DIVBYZERO:                        490         case FE_DIVBYZERO:
494           os << "Floating point divide by zero << 491           message << "Floating point divide by zero.";
495           break;                                  492           break;
496         case FE_OVERFLOW:                         493         case FE_OVERFLOW:
497           os << "Floating point overflow.";    << 494           message << "Floating point overflow.";
498           break;                                  495           break;
499         case FE_UNDERFLOW:                        496         case FE_UNDERFLOW:
500           os << "Floating point underflow.";   << 497           message << "Floating point underflow.";
501           break;                                  498           break;
502         case FE_INEXACT:                          499         case FE_INEXACT:
503           os << "Floating point inexact result << 500           message << "Floating point inexact result.";
504           break;                                  501           break;
505         case FE_INVALID:                          502         case FE_INVALID:
506           os << "Floating point invalid operat << 503           message << "Floating point invalid operation.";
507           break;                                  504           break;
508         default:                                  505         default:
509           os << "Unknown floating point except << 506           message << "Unknown floating point exception error: "
510              << ".";                           << 507                   << sinfo->si_code << ".";
511           break;                                  508           break;
512       }                                           509       }
513     }                                             510     }
514     else                                          511     else
515     {                                             512     {
516       os << "Unknown floating point exception" << 513       message << "Unknown floating point exception";
517       if(sinfo != nullptr)                     << 514       if(sinfo)
518         os << ": " << sinfo->si_code;          << 515         message << ": " << sinfo->si_code;
519       os << ". ";                              << 516       message << ". ";
520     }                                             517     }
521   }                                               518   }
522                                                   519 
523   os << '\n';                                  << 520   message << std::endl;
524                                                << 
525   auto bt = GetMangled<256, 3>([](const char*  << 
526   char prefix[64];                             << 
527   snprintf(prefix, 64, "[PID=%i, TID=%i]", (G4 << 
528            (G4int) G4Threading::G4GetThreadId( << 
529   std::size_t sz = 0;                          << 
530   for(auto& itr : bt)                          << 
531   {                                            << 
532     if(itr == nullptr)                         << 
533       break;                                   << 
534     if(strlen(itr) == 0)                       << 
535       break;                                   << 
536     ++sz;                                      << 
537   }                                            << 
538   os << "\nBacktrace:\n";                      << 
539   auto _w = std::log10(sz) + 1;                << 
540   for(std::size_t i = 0; i < sz; ++i)          << 
541   {                                            << 
542     os << prefix << "[" << std::setw(_w) << st << 
543        << std::setw(_w) << std::right << sz << << 
544        << '\n';                                << 
545   }                                            << 
546   os << std::flush;                            << 
547                                                << 
548   // exit action could cause more signals to b << 
549   // after the message has been printed        << 
550   try                                             521   try
551   {                                               522   {
                                                   >> 523     sigignore(sig);
552     ExitAction(sig);                              524     ExitAction(sig);
553   } catch(std::exception& e)                      525   } catch(std::exception& e)
554   {                                               526   {
555     std::cerr << "ExitAction(" << sig << ") th    527     std::cerr << "ExitAction(" << sig << ") threw an exception" << std::endl;
556     std::cerr << e.what() << std::endl;           528     std::cerr << e.what() << std::endl;
557   }                                               529   }
                                                   >> 530 
                                                   >> 531   auto bt = GetDemangled<256, 3>(FrameFunctor());
                                                   >> 532   std::stringstream prefix;
                                                   >> 533   prefix << "[PID=" << getpid() << ", TID=" << G4Threading::G4GetThreadId()
                                                   >> 534          << "]";
                                                   >> 535   std::vector<G4String> btvec;
                                                   >> 536   for(auto& itr : bt)
                                                   >> 537   {
                                                   >> 538     if(itr.length() > 0)
                                                   >> 539       btvec.emplace_back(std::move(itr));
                                                   >> 540   }
                                                   >> 541   std::stringstream serr;
                                                   >> 542   serr << "\nBacktrace:\n";
                                                   >> 543   auto _w = std::log10(btvec.size()) + 1;
                                                   >> 544   for(size_t i = 0; i < btvec.size(); ++i)
                                                   >> 545   {
                                                   >> 546     serr << prefix.str() << "[" << std::setw(_w) << std::right << i << '/'
                                                   >> 547          << std::setw(_w) << std::right << btvec.size() << "]> " << std::left
                                                   >> 548          << btvec.at(i) << '\n';
                                                   >> 549   }
                                                   >> 550   os << serr.str().c_str() << '\n';
                                                   >> 551   os << message.str() << std::flush;
558 }                                                 552 }
559                                                   553 
560 //--------------------------------------------    554 //----------------------------------------------------------------------------//
561                                                   555 
562 inline void G4Backtrace::Handler(G4int sig, si << 556 inline void G4Backtrace::Handler(int sig, siginfo_t* sinfo, void*)
563 {                                                 557 {
564   Message(sig, sinfo, std::cerr);              << 558   std::unique_lock<std::mutex> lk{ *(GetData().lock) };
565                                                   559 
566   char msg[1024];                              << 560   {
567   snprintf(msg, 1024, "%s", "\n");             << 561     std::stringstream msg;
                                                   >> 562     Message(sig, sinfo, msg);
                                                   >> 563     std::cerr << msg.str() << std::flush;
                                                   >> 564   }
568                                                   565 
569   if((sinfo != nullptr) && G4PSIGINFO_AVAILABL << 566   std::stringstream msg;
                                                   >> 567   msg << "\n\n";
                                                   >> 568 
                                                   >> 569   if(sinfo && G4PSIGINFO_AVAILABLE > 0)
570   {                                               570   {
571 #  if G4PSIGINFO_AVAILABLE > 0                    571 #  if G4PSIGINFO_AVAILABLE > 0
572     psiginfo(sinfo, msg);                      << 572     psiginfo(sinfo, msg.str().c_str());
573     fflush(stdout);                            << 
574     fflush(stderr);                            << 
575 #  endif                                          573 #  endif
576   }                                               574   }
577   else                                            575   else
578   {                                               576   {
579     std::cerr << msg << std::flush;            << 577     std::cerr << msg.str() << std::endl;
580   }                                               578   }
581                                                   579 
582   // ignore any termination signals               580   // ignore any termination signals
583   signal(SIGKILL, SIG_IGN);                    << 581   sigignore(SIGKILL);
584   signal(SIGTERM, SIG_IGN);                    << 582   sigignore(SIGTERM);
585   signal(SIGABRT, SIG_IGN);                    << 583   sigignore(SIGABRT);
586   abort();                                        584   abort();
587 }                                                 585 }
588                                                   586 
589 //--------------------------------------------    587 //----------------------------------------------------------------------------//
590                                                   588 
591 inline G4int G4Backtrace::Enable(const signal_ << 589 inline int G4Backtrace::Enable(const signal_set_t& _signals)
592 {                                                 590 {
593   static G4bool _first = true;                 << 591   static bool _first = true;
                                                   >> 592   std::unique_lock<std::mutex> lk{ *(GetData().lock) };
594   if(_first)                                      593   if(_first)
595   {                                               594   {
596     std::string _msg = "!!! G4Backtrace is act    595     std::string _msg = "!!! G4Backtrace is activated !!!";
597     std::stringstream _filler;                    596     std::stringstream _filler;
598     std::stringstream _spacer;                    597     std::stringstream _spacer;
599     _filler.fill('#');                            598     _filler.fill('#');
600     _filler << std::setw((G4int)_msg.length()) << 599     _filler << std::setw(_msg.length()) << "";
601     _spacer << std::setw(10) << "";               600     _spacer << std::setw(10) << "";
602     std::cout << "\n\n"                           601     std::cout << "\n\n"
603               << _spacer.str() << _filler.str(    602               << _spacer.str() << _filler.str() << "\n"
604               << _spacer.str() << _msg << "\n"    603               << _spacer.str() << _msg << "\n"
605               << _spacer.str() << _filler.str(    604               << _spacer.str() << _filler.str() << "\n\n"
606               << std::flush;                      605               << std::flush;
607   }                                               606   }
608   _first  = false;                                607   _first  = false;
609   G4int cnt = 0;                               << 608   int cnt = 0;
610   for(auto& itr : _signals)                       609   for(auto& itr : _signals)
611   {                                               610   {
612     if(itr < 0)                                   611     if(itr < 0)
613       continue;                                   612       continue;
614     if(GetData().is_active[itr])                  613     if(GetData().is_active[itr])
615       continue;                                   614       continue;
616     ++cnt;                                        615     ++cnt;
617     sigfillset(&(GetData().current[itr].sa_mas    616     sigfillset(&(GetData().current[itr].sa_mask));
618     sigdelset(&(GetData().current[itr].sa_mask    617     sigdelset(&(GetData().current[itr].sa_mask), itr);
619     GetData().current[itr].sa_sigaction = &Han    618     GetData().current[itr].sa_sigaction = &Handler;
620     GetData().current[itr].sa_flags     = SA_S    619     GetData().current[itr].sa_flags     = SA_SIGINFO;
621     sigaction(itr, &(GetData().current[itr]),     620     sigaction(itr, &(GetData().current[itr]), &(GetData().previous[itr]));
622   }                                               621   }
623   return cnt;                                     622   return cnt;
624 }                                                 623 }
625                                                   624 
626 //--------------------------------------------    625 //----------------------------------------------------------------------------//
627                                                   626 
628 inline G4int G4Backtrace::Enable(const std::st << 627 inline int G4Backtrace::Enable(const std::string& _signals)
629 {                                                 628 {
630   if(_signals.empty())                            629   if(_signals.empty())
631     return 0;                                     630     return 0;
632                                                   631 
633   auto _add_signal = [](std::string sig, signa    632   auto _add_signal = [](std::string sig, signal_set_t& _targ) {
634     if(!sig.empty())                              633     if(!sig.empty())
635     {                                             634     {
636       for(auto& itr : sig)                        635       for(auto& itr : sig)
637         itr = (char)std::toupper(itr);         << 636         itr = toupper(itr);
638       _targ.insert(G4Backtrace::GetSignal(sig)    637       _targ.insert(G4Backtrace::GetSignal(sig));
639     }                                             638     }
640   };                                              639   };
641                                                   640 
642   const std::regex wsp_re("[ ,;:\t\n]+");         641   const std::regex wsp_re("[ ,;:\t\n]+");
643   auto _maxid  = GetData().identifiers.size();    642   auto _maxid  = GetData().identifiers.size();
644   auto _result = std::vector<std::string>(_max    643   auto _result = std::vector<std::string>(_maxid, "");
645   std::copy(                                      644   std::copy(
646     std::sregex_token_iterator(_signals.begin(    645     std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
647     std::sregex_token_iterator(), _result.begi    646     std::sregex_token_iterator(), _result.begin());
648   signal_set_t _sigset{};                         647   signal_set_t _sigset{};
649   for(auto& itr : _result)                        648   for(auto& itr : _result)
650     _add_signal(itr, _sigset);                    649     _add_signal(itr, _sigset);
651   return Enable(_sigset);                         650   return Enable(_sigset);
652 }                                                 651 }
653                                                   652 
654 //--------------------------------------------    653 //----------------------------------------------------------------------------//
655                                                   654 
656 inline G4int G4Backtrace::Disable(signal_set_t << 655 inline int G4Backtrace::Disable(signal_set_t _signals)
657 {                                                 656 {
                                                   >> 657   std::unique_lock<std::mutex> lk{ *(GetData().lock) };
                                                   >> 658 
658   if(_signals.empty())                            659   if(_signals.empty())
659   {                                               660   {
660     for(auto& itr : GetData().is_active)          661     for(auto& itr : GetData().is_active)
661       _signals.insert(itr.first);                 662       _signals.insert(itr.first);
662   }                                               663   }
663                                                   664 
664   G4int cnt = 0;                               << 665   int cnt = 0;
665   for(auto& itr : _signals)                       666   for(auto& itr : _signals)
666   {                                               667   {
667     if(itr < 0)                                   668     if(itr < 0)
668       continue;                                   669       continue;
669     if(!GetData().is_active[itr])                 670     if(!GetData().is_active[itr])
670       continue;                                   671       continue;
671     ++cnt;                                        672     ++cnt;
672     sigaction(itr, &(GetData().previous[itr]),    673     sigaction(itr, &(GetData().previous[itr]), nullptr);
673     GetData().current.erase(itr);                 674     GetData().current.erase(itr);
674     GetData().is_active[itr] = false;             675     GetData().is_active[itr] = false;
675   }                                               676   }
676   return cnt;                                     677   return cnt;
677 }                                                 678 }
678                                                   679 
679 //--------------------------------------------    680 //----------------------------------------------------------------------------//
680                                                   681 
681 inline G4int G4Backtrace::GetSignal(const std: << 682 inline int G4Backtrace::GetSignal(const std::string& sid)
682 {                                                 683 {
683   for(auto&& itr : GetData().identifiers)         684   for(auto&& itr : GetData().identifiers)
684   {                                               685   {
685     if(std::get<0>(itr) == sid)                   686     if(std::get<0>(itr) == sid)
686       return std::get<1>(itr);                    687       return std::get<1>(itr);
687   }                                               688   }
688   return -1;                                      689   return -1;
689 }                                                 690 }
690                                                   691 
691 //--------------------------------------------    692 //----------------------------------------------------------------------------//
692                                                   693 
693 inline std::string G4Backtrace::Description(G4 << 694 inline std::string G4Backtrace::Description(int sig)
694 {                                                 695 {
695   for(auto&& itr : GetData().identifiers)         696   for(auto&& itr : GetData().identifiers)
696   {                                               697   {
697     if(std::get<1>(itr) == sig)                   698     if(std::get<1>(itr) == sig)
698     {                                             699     {
699       std::stringstream ss;                       700       std::stringstream ss;
700       ss << " signal = " << std::setw(8) << st    701       ss << " signal = " << std::setw(8) << std::get<0>(itr)
701          << ", value = " << std::setw(4) << st    702          << ", value = " << std::setw(4) << std::get<1>(itr)
702          << ", description = " << std::get<2>(    703          << ", description = " << std::get<2>(itr);
703       return ss.str();                            704       return ss.str();
704     }                                             705     }
705   }                                               706   }
706   std::stringstream ss;                           707   std::stringstream ss;
707   ss << " signal = " << std::setw(8) << "unkno    708   ss << " signal = " << std::setw(8) << "unknown"
708      << ", value = " << std::setw(4) << sig;      709      << ", value = " << std::setw(4) << sig;
709   return ss.str();                                710   return ss.str();
710 }                                                 711 }
711                                                   712 
712 //--------------------------------------------    713 //----------------------------------------------------------------------------//
713                                                   714 
714 #else                                             715 #else
715                                                   716 
716 #  include <array>                                717 #  include <array>
717 #  include <functional>                           718 #  include <functional>
718 #  include <map>                                  719 #  include <map>
719 #  include <set>                                  720 #  include <set>
720 #  include <string>                               721 #  include <string>
721 #  include <tuple>                                722 #  include <tuple>
722 #  include <vector>                               723 #  include <vector>
723                                                   724 
724 // dummy implementation                           725 // dummy implementation
725 class G4Backtrace                                 726 class G4Backtrace
726 {                                                 727 {
727  public:                                          728  public:
728   struct fake_siginfo                             729   struct fake_siginfo
729   {};                                             730   {};
730   struct fake_sigaction                           731   struct fake_sigaction
731   {};                                             732   {};
732                                                   733 
733   using siginfo_t = fake_siginfo;                 734   using siginfo_t = fake_siginfo;
734   using sigaction_t = fake_sigaction;             735   using sigaction_t = fake_sigaction;
735   using exit_action_t = std::function<void(G4i << 736   using exit_action_t = std::function<void(int)>;
736   using frame_func_t = std::function<G4String(    737   using frame_func_t = std::function<G4String(const char*)>;
737   using signal_set_t = std::set<G4int>;        << 738   using signal_set_t = std::set<int>;
738                                                   739 
739  public:                                          740  public:
740   struct actions                                  741   struct actions
741   {                                               742   {
742     using id_entry_t = std::tuple<std::string, << 743     using id_entry_t = std::tuple<std::string, int, std::string>;
743     using id_list_t = std::vector<id_entry_t>;    744     using id_list_t = std::vector<id_entry_t>;
744                                                   745 
745     std::map<G4int, G4bool> is_active = {};    << 746     std::map<int, bool> is_active = {};
746     std::map<G4int, sigaction_t> current = {}; << 747     std::map<int, sigaction_t> current = {};
747     std::map<G4int, sigaction_t> previous = {} << 748     std::map<int, sigaction_t> previous = {};
748     std::vector<exit_action_t> exit_actions =     749     std::vector<exit_action_t> exit_actions = {};
749     const id_list_t identifiers = {};             750     const id_list_t identifiers = {};
750   };                                              751   };
751                                                   752 
752  public:                                          753  public:
753   static void Handler(G4int, siginfo_t*, void* << 754   static void Handler(int, siginfo_t*, void*) {}
754   static void Message(G4int, siginfo_t*, std:: << 755   static void Message(int, siginfo_t*, std::ostream&) {}
755   static void ExitAction(G4int) {}             << 756   static void ExitAction(int) {}
756   static G4int Enable(const std::string&) { re << 757   static int Enable(const std::string&) { return 0; }
757   static G4int Enable(const signal_set_t& = De << 758   static int Enable(const signal_set_t& = DefaultSignals()) { return 0; }
758   static G4int Disable(signal_set_t = {}) { re << 759   static int Disable(signal_set_t = {}) { return 0; }
759   static G4int GetSignal(const std::string&) { << 760   static int GetSignal(const std::string&) { return -1; }
760   static std::string Description(G4int) { retu << 761   static std::string Description(int) { return std::string{}; }
761                                                   762 
762   template <typename FuncT>                       763   template <typename FuncT>
763   static void AddExitAction(FuncT&&)              764   static void AddExitAction(FuncT&&)
764   {}                                              765   {}
765                                                   766 
766   template <std::size_t Depth, std::size_t Off << 767   template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
767   static std::array<G4ResultOf_t<FuncT, const  << 768   static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetMangled(
768     FuncT&& func = FrameFunctor())                769     FuncT&& func = FrameFunctor())
769   {                                               770   {
770     using type = G4ResultOf_t<FuncT, const cha << 771     using type = G4ResultOf_t<FuncT(const char*)>;
771     auto ret = std::array<type, Depth>{};         772     auto ret = std::array<type, Depth>{};
772     ret.fill(func(""));                           773     ret.fill(func(""));
773     return ret;                                   774     return ret;
774   }                                               775   }
775                                                   776 
776   template <std::size_t Depth, std::size_t Off << 777   template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
777   static std::array<G4ResultOf_t<FuncT, const  << 778   static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetDemangled(
778     FuncT&& func = FrameFunctor())                779     FuncT&& func = FrameFunctor())
779   {                                               780   {
780     using type = G4ResultOf_t<FuncT, const cha << 781     using type = G4ResultOf_t<FuncT(const char*)>;
781     auto ret = std::array<type, Depth>{};         782     auto ret = std::array<type, Depth>{};
782     ret.fill(func(""));                           783     ret.fill(func(""));
783     return ret;                                   784     return ret;
784   }                                               785   }
785                                                   786 
786   // a functor called for each frame in the ba    787   // a functor called for each frame in the backtrace
787   static frame_func_t& FrameFunctor()             788   static frame_func_t& FrameFunctor()
788   {                                               789   {
789     static frame_func_t _instance = [](const c    790     static frame_func_t _instance = [](const char* _s) { return G4String(_s); };
790     return _instance;                             791     return _instance;
791   }                                               792   }
792                                                   793 
793   // default set of signals                       794   // default set of signals
794   static signal_set_t& DefaultSignals()           795   static signal_set_t& DefaultSignals()
795   {                                               796   {
796     static signal_set_t _instance = {};           797     static signal_set_t _instance = {};
797     return _instance;                             798     return _instance;
798   }                                               799   }
799                                                   800 
800   static actions& GetData()                       801   static actions& GetData()
801   {                                               802   {
802     static auto _instance = actions{};            803     static auto _instance = actions{};
803     return _instance;                             804     return _instance;
804   }                                               805   }
805 };                                                806 };
806                                                   807 
807 //--------------------------------------------    808 //----------------------------------------------------------------------------//
808                                                   809 
809 #endif  // G4SIGNAL_AVAILABLE                     810 #endif  // G4SIGNAL_AVAILABLE
810 #endif  // G4Backtrace_hh                         811 #endif  // G4Backtrace_hh
811                                                   812