Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
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