Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4Backtrace.hh
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// G4Backtrace
27//
28// Description:
29//
30// Prints backtraces after signals are caught. Available on Unix.
31//
32// Usage:
33// A standard set of signals are enabled by default:
34//
35// SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
36//
37// These should not interfere with debuggers and/or G4FPEDetection.
38// In order to turn off handling for one or more signals, one can do:
39//
40// G4Backtrace::DefaultSignals() = std::set<int>{};
41// G4Backtrace::DefaultSignals() = std::set<int>{ SIGSEGV };
42//
43// and so on, *before* creating the run-manager. After the run-manager
44// has been created, one should disable the signals:
45//
46// G4Backtrace::Disable(G4Backtrace::DefaultSignals());
47//
48// Additionally, at runtime, the environment variable "G4BACKTRACE" can
49// be set to select a specific set of signals or none, e.g. in bash:
50//
51// export G4BACKTRACE="SIGQUIT,SIGSEGV"
52// export G4BACKTRACE="none"
53//
54// The environment variable is case-insensitive and can use any of the
55// following delimiters: space, comma, semi-colon, colon
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) || 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) || 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
102template <typename FuncT, typename... ArgTypes>
103using G4ResultOf_t = std::invoke_result_t<FuncT, ArgTypes...>;
104
105// compatible OS and compiler
106#if defined(G4UNIX) && \
107 (defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER))
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 >= 200809L
118# define G4PSIGINFO_AVAILABLE 1
119# else
120# define G4PSIGINFO_AVAILABLE 0
121# endif
122#endif
123
124//----------------------------------------------------------------------------//
125
126inline 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, nullptr, nullptr, &_status);
132 if((_ret != nullptr) && _status == 0)
133 return G4String(const_cast<const char*>(_ret));
134 return _str;
135#else
136 return _str;
137#endif
138}
139
140//----------------------------------------------------------------------------//
141
142inline G4String G4Demangle(const G4String& _str)
143{
144 return G4Demangle(_str.c_str());
145}
146
147//----------------------------------------------------------------------------//
148
149template <typename Tp>
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 standard so we are defining
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 nevertheless appears on most other
170// UNIX systems, where its default action is typically to terminate the
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
219class G4Backtrace
220{
221 public:
222 using sigaction_t = struct sigaction;
223 using exit_action_t = std::function<void(G4int)>;
224 using frame_func_t = std::function<G4String(const char*)>;
225 using signal_set_t = std::set<G4int>;
226
227 public:
228 struct actions
229 {
230 using id_entry_t = std::tuple<std::string, G4int, 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 line hangup"),
239 id_entry_t("SIGINT", SIGINT, "interrupt program"),
240 id_entry_t("SIGQUIT", SIGQUIT, "quit program"),
241 id_entry_t("SIGILL", SIGILL, "illegal instruction"),
242 id_entry_t("SIGTRAP", SIGTRAP, "trace trap"),
243 id_entry_t("SIGABRT", SIGABRT, "abort program (formerly SIGIOT)"),
244 id_entry_t("SIGEMT", SIGEMT, "emulate instruction executed"),
245 id_entry_t("SIGFPE", SIGFPE, "floating-point exception"),
246 id_entry_t("SIGKILL", SIGKILL, "kill program"),
247 id_entry_t("SIGBUS", SIGBUS, "bus error"),
248 id_entry_t("SIGSEGV", SIGSEGV, "segmentation violation"),
249 id_entry_t("SIGSYS", SIGSYS, "non-existent system call invoked"),
250 id_entry_t("SIGPIPE", SIGPIPE, "write on a pipe with no reader"),
251 id_entry_t("SIGALRM", SIGALRM, "real-time timer expired"),
252 id_entry_t("SIGTERM", SIGTERM, "software termination signal"),
253 id_entry_t("SIGURG", SIGURG, "urgent condition present on socket"),
254 id_entry_t("SIGSTOP", SIGSTOP, "stop (cannot be caught or ignored)"),
255 id_entry_t("SIGTSTP", SIGTSTP, "stop signal generated from keyboard"),
256 id_entry_t("SIGCONT", SIGCONT, "continue after stop"),
257 id_entry_t("SIGCHLD", SIGCHLD, "child status has changed"),
258 id_entry_t("SIGTTIN", SIGTTIN,
259 "background read attempted from control terminal"),
260 id_entry_t("SIGTTOU", SIGTTOU,
261 "background write attempted to control terminal"),
262 id_entry_t("SIGIO ", SIGIO, "I/O is possible on a descriptor"),
263 id_entry_t("SIGXCPU", SIGXCPU, "cpu time limit exceeded"),
264 id_entry_t("SIGXFSZ", SIGXFSZ, "file size limit exceeded"),
265 id_entry_t("SIGVTALRM", SIGVTALRM, "virtual time alarm"),
266 id_entry_t("SIGPROF", SIGPROF, "profiling timer alarm"),
267 id_entry_t("SIGWINCH", SIGWINCH, "Window size change"),
268 id_entry_t("SIGINFO", SIGINFO, "status request from keyboard"),
269 id_entry_t("SIGUSR1", SIGUSR1, "User defined signal 1"),
270 id_entry_t("SIGUSR2", SIGUSR2, "User defined signal 2")
271 };
272 };
273
274 public:
275 // a functor called for each frame in the backtrace
276 static frame_func_t& FrameFunctor();
277 // default set of signals
279 // the signal handler
280 static void Handler(G4int sig, siginfo_t* sinfo, void* context);
281 // information message about the signal, performs exit-actions
282 // and prints back-trace
283 static void Message(G4int sig, siginfo_t* sinfo, std::ostream&);
284 // calls user-provided functions after signal is caught but before abort
285 static void ExitAction(G4int sig);
286 // enable signals via a string (which is tokenized)
287 static G4int Enable(const std::string&);
288 // enable signals via set of integers, anything less than zero is ignored
289 static G4int Enable(const signal_set_t& _signals = DefaultSignals());
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 offset parameter is used
302 // to ignore initial frames (such as this function). A callback
303 // can be provided to inspect and/or tweak the frame string
304 template <std::size_t Depth, std::size_t Offset = 0, typename FuncT = frame_func_t>
305 static std::array<G4ResultOf_t<FuncT, const char*>, Depth> GetMangled(
306 FuncT&& func = FrameFunctor());
307
308 // gets a demangled backtrace of "Depth" frames. The offset parameter is
309 // used to ignore initial frames (such as this function). A callback
310 // can be provided to inspect and/or tweak the frame string
311 template <std::size_t Depth, std::size_t Offset = 0, typename FuncT = frame_func_t>
312 static std::array<G4ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
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 backtrace
327{
328 static frame_func_t _instance = [](const char* inp) { return G4String(inp); };
329 return _instance;
330}
331
332//----------------------------------------------------------------------------//
333
334// default set of signals
336{
337 static signal_set_t _instance = { SIGQUIT, SIGILL, SIGABRT,
338 SIGKILL, SIGBUS, SIGSEGV };
339 return _instance;
340}
341
342//----------------------------------------------------------------------------//
343
344template <typename FuncT>
345inline void G4Backtrace::AddExitAction(FuncT&& func)
346{
347 GetData().exit_actions.emplace_back(std::forward<FuncT>(func));
348}
349
350//----------------------------------------------------------------------------//
351
352inline void G4Backtrace::ExitAction(G4int sig)
353{
354 for(auto& itr : GetData().exit_actions)
355 itr(sig);
356}
357
358//----------------------------------------------------------------------------//
359
360template <std::size_t Depth, std::size_t Offset, typename FuncT>
361inline std::array<G4ResultOf_t<FuncT, const char*>, Depth>
362G4Backtrace::GetMangled(FuncT&& func)
363{
364 static_assert((Depth - Offset) >= 1, "Error Depth - Offset should be >= 1");
365
367 // destination
368 std::array<type, Depth> btrace;
369 btrace.fill((std::is_pointer<type>::value) ? nullptr : type{});
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 + Offset);
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() + Offset, (G4int)n);
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
395template <std::size_t Depth, std::size_t Offset, typename FuncT>
396inline std::array<G4ResultOf_t<FuncT, const char*>, Depth>
397G4Backtrace::GetDemangled(FuncT&& func)
398{
399 auto demangle_bt = [&](const char* cstr) {
400 auto _trim = [](std::string& _sub, std::size_t& _len) {
401 std::size_t _pos = 0;
402 while((_pos = _sub.find_first_of(' ')) == 0)
403 {
404 _sub = _sub.erase(_pos, 1);
405 --_len;
406 }
407 while((_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
408 {
409 _sub = _sub.substr(0, _sub.length() - 1);
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::string::npos)
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
452inline void G4Backtrace::Message(G4int sig, siginfo_t* sinfo, std::ostream& os)
453{
454 // try to avoid as many dynamic allocations as possible here to avoid
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 mapped object.";
476 break;
477 default:
478 os << "Unknown segmentation fault error: " << sinfo->si_code << ".";
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 operation.";
507 break;
508 default:
509 os << "Unknown floating point exception error: " << sinfo->si_code
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* _s) { return _s; });
526 char prefix[64];
527 snprintf(prefix, 64, "[PID=%i, TID=%i]", (G4int) getpid(),
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) << std::right << i << '/'
543 << std::setw(_w) << std::right << sz << "]> " << std::left << bt.at(i)
544 << '\n';
545 }
546 os << std::flush;
547
548 // exit action could cause more signals to be raise so make sure this is done
549 // after the message has been printed
550 try
551 {
552 ExitAction(sig);
553 } catch(std::exception& e)
554 {
555 std::cerr << "ExitAction(" << sig << ") threw an exception" << std::endl;
556 std::cerr << e.what() << std::endl;
557 }
558}
559
560//----------------------------------------------------------------------------//
561
562inline void G4Backtrace::Handler(G4int sig, siginfo_t* sinfo, void*)
563{
564 Message(sig, sinfo, std::cerr);
565
566 char msg[1024];
567 snprintf(msg, 1024, "%s", "\n");
568
569 if((sinfo != nullptr) && G4PSIGINFO_AVAILABLE > 0)
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
591inline G4int G4Backtrace::Enable(const signal_set_t& _signals)
592{
593 static G4bool _first = true;
594 if(_first)
595 {
596 std::string _msg = "!!! G4Backtrace is activated !!!";
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() << "\n"
604 << _spacer.str() << _msg << "\n"
605 << _spacer.str() << _filler.str() << "\n\n"
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_mask));
618 sigdelset(&(GetData().current[itr].sa_mask), itr);
619 GetData().current[itr].sa_sigaction = &Handler;
620 GetData().current[itr].sa_flags = SA_SIGINFO;
621 sigaction(itr, &(GetData().current[itr]), &(GetData().previous[itr]));
622 }
623 return cnt;
624}
625
626//----------------------------------------------------------------------------//
627
628inline G4int G4Backtrace::Enable(const std::string& _signals)
629{
630 if(_signals.empty())
631 return 0;
632
633 auto _add_signal = [](std::string sig, signal_set_t& _targ) {
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>(_maxid, "");
645 std::copy(
646 std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
647 std::sregex_token_iterator(), _result.begin());
648 signal_set_t _sigset{};
649 for(auto& itr : _result)
650 _add_signal(itr, _sigset);
651 return Enable(_sigset);
652}
653
654//----------------------------------------------------------------------------//
655
656inline G4int G4Backtrace::Disable(signal_set_t _signals)
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]), nullptr);
673 GetData().current.erase(itr);
674 GetData().is_active[itr] = false;
675 }
676 return cnt;
677}
678
679//----------------------------------------------------------------------------//
680
681inline G4int G4Backtrace::GetSignal(const std::string& sid)
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
693inline std::string G4Backtrace::Description(G4int sig)
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) << std::get<0>(itr)
701 << ", value = " << std::setw(4) << std::get<1>(itr)
702 << ", description = " << std::get<2>(itr);
703 return ss.str();
704 }
705 }
706 std::stringstream ss;
707 ss << " signal = " << std::setw(8) << "unknown"
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
726{
727 public:
729 {};
731 {};
732
735 using exit_action_t = std::function<void(G4int)>;
736 using frame_func_t = std::function<G4String(const char*)>;
737 using signal_set_t = std::set<G4int>;
738
739 public:
740 struct actions
741 {
742 using id_entry_t = std::tuple<std::string, G4int, 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 = {};
750 };
751
752 public:
753 static void Handler(G4int, siginfo_t*, void*) {}
754 static void Message(G4int, siginfo_t*, std::ostream&) {}
755 static void ExitAction(G4int) {}
756 static G4int Enable(const std::string&) { return 0; }
757 static G4int Enable(const signal_set_t& = DefaultSignals()) { return 0; }
758 static G4int Disable(signal_set_t = {}) { return 0; }
759 static G4int GetSignal(const std::string&) { return -1; }
760 static std::string Description(G4int) { return std::string{}; }
761
762 template <typename FuncT>
763 static void AddExitAction(FuncT&&)
764 {}
765
766 template <std::size_t Depth, std::size_t Offset = 0, typename FuncT = frame_func_t>
767 static std::array<G4ResultOf_t<FuncT, const char*>, Depth> GetMangled(
768 FuncT&& func = FrameFunctor())
769 {
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 Offset = 0, typename FuncT = frame_func_t>
777 static std::array<G4ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
778 FuncT&& func = FrameFunctor())
779 {
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 backtrace
788 {
789 static frame_func_t _instance = [](const char* _s) { return G4String(_s); };
790 return _instance;
791 }
792
793 // default set of signals
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
std::invoke_result_t< FuncT, ArgTypes... > G4ResultOf_t
#define G4PSIGINFO_AVAILABLE
G4String G4Demangle()
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
static G4int Enable(const signal_set_t &=DefaultSignals())
static G4int Disable(signal_set_t={})
fake_sigaction sigaction_t
static std::array< G4ResultOf_t< FuncT, const char * >, Depth > GetDemangled(FuncT &&func=FrameFunctor())
static signal_set_t & DefaultSignals()
std::set< G4int > signal_set_t
static G4int Enable(const std::string &)
static std::array< G4ResultOf_t< FuncT, const char * >, Depth > GetMangled(FuncT &&func=FrameFunctor())
static void AddExitAction(FuncT &&)
std::function< void(G4int)> exit_action_t
static std::string Description(G4int)
static frame_func_t & FrameFunctor()
static void Message(G4int, siginfo_t *, std::ostream &)
static void ExitAction(G4int)
static actions & GetData()
static void Handler(G4int, siginfo_t *, void *)
fake_siginfo siginfo_t
std::function< G4String(const char *)> frame_func_t
static G4int GetSignal(const std::string &)
G4int G4GetThreadId()
std::vector< exit_action_t > exit_actions
const id_list_t identifiers
std::map< G4int, sigaction_t > current
std::vector< id_entry_t > id_list_t
std::map< G4int, G4bool > is_active
std::tuple< std::string, G4int, std::string > id_entry_t
std::map< G4int, sigaction_t > previous