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.3.p3)


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