File indexing completed on 2026-09-19 08:31:49
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <DD4hep/Printout.h>
0016 #include <DD4hep/SignalHandler.h>
0017
0018 #include <csignal>
0019 #include <map>
0020 #include <memory>
0021 #include <string>
0022 #include <vector>
0023 #include <unistd.h>
0024 #include <execinfo.h>
0025
0026 using namespace dd4hep;
0027
0028 using signal_handler_t = SignalHandler::signal_handler_t;
0029
0030 namespace {
0031 static bool s_exit_handler_print = true;
0032 static bool s_exit_handler_active = false;
0033 static bool s_exit_handler_backtrace = false;
0034 static bool s_exit_handler_sleep_on_fatal = false;
0035
0036 template<class T> union func_cast {
0037 void* ptr;
0038 T fun;
0039 explicit func_cast(T t) { fun = t; }
0040 explicit func_cast(void* t) { ptr = t; }
0041 };
0042 }
0043
0044
0045
0046
0047
0048
0049
0050 class SignalHandler::implementation {
0051 protected:
0052 struct sig_entry_t {
0053 void* user_context { nullptr };
0054 signal_handler_t user_handler { nullptr };
0055 };
0056 struct sig_handler_t {
0057 std::string name { };
0058 struct sigaction old_action { };
0059 struct sigaction handler_action { };
0060 std::vector<sig_entry_t> user_handlers { };
0061 };
0062
0063 public:
0064 typedef std::map<int, sig_handler_t> SigMap;
0065 SigMap m_map;
0066
0067 public:
0068
0069 implementation();
0070
0071 ~implementation();
0072
0073 static implementation& instance();
0074
0075 void init();
0076
0077 void install(int num, const std::string& name, struct sigaction& action);
0078
0079 int subscribe(int signum, void* user_context, signal_handler_t handler);
0080
0081 int unsubscribe(int signum, void* user_context);
0082
0083 void back_trace(int );
0084
0085 static void handler(int signum, siginfo_t *info,void * );
0086 };
0087
0088
0089 SignalHandler::implementation::implementation() {
0090 }
0091
0092
0093 SignalHandler::implementation::~implementation() {
0094 }
0095
0096
0097 SignalHandler::implementation& SignalHandler::implementation::instance() {
0098 static std::unique_ptr<implementation> imp;
0099 if ( !imp ) {
0100 imp = std::make_unique<implementation>();
0101 }
0102 return *imp;
0103 }
0104
0105
0106 void SignalHandler::implementation::init() {
0107 struct sigaction new_action;
0108 sigemptyset(&new_action.sa_mask);
0109 new_action.sa_handler = 0;
0110 new_action.sa_sigaction = handler;
0111 new_action.sa_flags = SA_SIGINFO;
0112
0113 install(SIGILL, "SIGILL", new_action);
0114 install(SIGINT, "SIGINT", new_action);
0115 install(SIGTERM, "SIGTERM", new_action);
0116 install(SIGHUP, "SIGHUP", new_action);
0117
0118 install(SIGQUIT, "SIGQUIT", new_action);
0119 install(SIGBUS, "SIGBUS", new_action);
0120 install(SIGXCPU, "SIGXCPU", new_action);
0121 sigaddset(&new_action.sa_mask,SIGSEGV);
0122 sigaddset(&new_action.sa_mask,SIGABRT);
0123 sigaddset(&new_action.sa_mask,SIGFPE);
0124 install(SIGABRT, "SIGABRT", new_action);
0125 install(SIGFPE, "SIGFPE", new_action);
0126 install(SIGSEGV, "SIGSEGV", new_action);
0127 }
0128
0129
0130 int SignalHandler::implementation::subscribe(int signum, void* user_context, signal_handler_t user_handler) {
0131 if ( m_map.empty() ) {
0132 this->init();
0133 }
0134 auto ihandler = m_map.find(signum);
0135 if ( ihandler == m_map.end() ) {
0136 char text[32];
0137 struct sigaction new_action;
0138 sigemptyset(&new_action.sa_mask);
0139 new_action.sa_handler = 0;
0140 new_action.sa_sigaction = SignalHandler::implementation::handler;
0141 new_action.sa_flags = SA_SIGINFO;
0142 ::snprintf(text, sizeof(text),"%08X",signum);
0143 install(signum, text, new_action);
0144 ihandler = m_map.find(signum);
0145 }
0146 if ( ihandler != m_map.end() ) {
0147 sig_entry_t entry {user_context, user_handler};
0148 ihandler->second.user_handlers.emplace_back(entry);
0149 return 1;
0150 }
0151 return 0;
0152 }
0153
0154
0155 int SignalHandler::implementation::unsubscribe(int signum, void* user_context) {
0156 auto ihandler = m_map.find(signum);
0157 if ( ihandler != m_map.end() ) {
0158 auto & handlers = ihandler->second.user_handlers;
0159 for( auto it = handlers.begin(); it != handlers.end(); ++it ) {
0160 if ( it->user_context == user_context ) {
0161 handlers.erase(it);
0162 return 1;
0163 }
0164 }
0165 }
0166 return 0;
0167 }
0168
0169
0170 void SignalHandler::implementation::back_trace(int ) {
0171 if ( s_exit_handler_backtrace ) {
0172 void *bt[256];
0173 char text[512];
0174 int bt_size = ::backtrace(bt, sizeof(bt) / sizeof(void *));
0175 size_t len = ::snprintf(text, sizeof(text), "\n[INFO] (ExitSignalHandler) %s\n",
0176 "---------------------- Backtrace ----------------------\n");
0177 text[sizeof(text)-2] = '\n';
0178 text[sizeof(text)-1] = 0;
0179 ::write(STDERR_FILENO, text, len);
0180 len = ::snprintf(text, sizeof(text), "[INFO] Number of elements in backtrace: %d\n", bt_size);
0181 text[sizeof(text)-2] = '\n';
0182 text[sizeof(text)-1] = 0;
0183 ::write(STDERR_FILENO, text, len);
0184 ::backtrace_symbols_fd(bt, bt_size, STDERR_FILENO);
0185 for (int i = 0; i < bt_size; i++) {
0186 len = ::snprintf(text,sizeof(text),"[INFO] (SignalHandler) %02d --> %p\n", i, bt[i]);
0187 text[sizeof(text)-2] = '\n';
0188 text[sizeof(text)-1] = 0;
0189 ::write(STDERR_FILENO, text, len);
0190 }
0191 }
0192 }
0193
0194
0195 void SignalHandler::implementation::install(int num, const std::string& name, struct sigaction& action) {
0196 auto& action_entry = m_map[num];
0197 int res = ::sigaction (num, &action, &action_entry.old_action);
0198 if ( res != 0 ) {
0199 char text[512];
0200 auto len = ::snprintf(text,sizeof(text),"Failed to install exit handler for %s", name.c_str());
0201 text[sizeof(text)-2] = '\n';
0202 text[sizeof(text)-1] = 0;
0203 ::write(STDERR_FILENO, text, len);
0204 return;
0205 }
0206 action_entry.handler_action = action;
0207 action_entry.name = name;
0208 }
0209
0210
0211 void SignalHandler::implementation::handler(int signum, siginfo_t *info, void *ptr) {
0212 SigMap& m = instance().m_map;
0213 SigMap::iterator iter_handler = m.find(signum);
0214 s_exit_handler_active = true;
0215 if ( iter_handler != m.end() ) {
0216 auto hdlr = iter_handler->second.old_action.sa_handler;
0217 func_cast<void (*)(int)> dsc0(hdlr);
0218 func_cast<void (*)(int,siginfo_t*, void*)> dsc(dsc0.ptr);
0219
0220 if ( s_exit_handler_print ) {{
0221 char text[512];
0222 size_t len = ::snprintf(text,sizeof(text),
0223 "[FATAL] (SignalHandler) Handle signal: %d [%s] Old action:%p Mem:%p Code:%08X\n",
0224 signum,iter_handler->second.name.c_str(),dsc.ptr,info->si_addr,info->si_code);
0225 text[sizeof(text)-2] = '\n';
0226 text[sizeof(text)-1] = 0;
0227 ::write(STDERR_FILENO,text,len);
0228
0229 if ( s_exit_handler_sleep_on_fatal ) {
0230 bool _s_sleep = true;
0231 len = ::snprintf(text,sizeof(text),
0232 "[FATAL] (SignalHandler) Sleeping for debugging.... %s\n",
0233 _s_sleep ? "YES" : "NO");
0234 text[sizeof(text)-2] = '\n';
0235 text[sizeof(text)-1] = 0;
0236 ::write(STDERR_FILENO,text,len);
0237 while ( _s_sleep ) ::usleep(100000);
0238 }
0239 }
0240 if ( !iter_handler->second.user_handlers.empty() ) {
0241 auto& handlers = iter_handler->second.user_handlers;
0242 for( auto ih = handlers.rbegin(); ih != handlers.rend(); ++ih ) {
0243 if ( ih->user_handler ) {
0244 bool ret = (*(ih->user_handler))(ih->user_context, signum);
0245 if ( ret ) {
0246 return;
0247 }
0248
0249 }
0250
0251 auto& entry = iter_handler->second.old_action;
0252 if ( entry.sa_handler )
0253 (*entry.sa_handler)(signum);
0254 else if ( entry.sa_sigaction )
0255 (*entry.sa_sigaction)(signum, info, ptr);
0256 }
0257 }
0258 if ( signum == SIGSEGV || signum == SIGBUS || signum == SIGILL || signum == SIGABRT ) {
0259 instance().back_trace(signum);
0260 }
0261 else if ( info->si_signo == SIGSEGV || info->si_signo == SIGBUS || info->si_signo == SIGILL || info->si_signo == SIGABRT ) {
0262 instance().back_trace(info->si_signo);
0263 }
0264 }
0265 if ( signum == SIGINT || signum == SIGHUP || signum == SIGFPE || signum == SIGPIPE ) {
0266 if ( dsc.fun && (dsc0.fun != SIG_IGN) )
0267 dsc.fun(signum, info, ptr);
0268 else if ( signum == SIGHUP )
0269 ::_exit(128+signum);
0270 }
0271 else if ( signum == SIGSEGV && hdlr && hdlr != SIG_IGN && hdlr != SIG_DFL ) {
0272 ::_exit(128+signum);
0273 }
0274 else if ( hdlr && hdlr != SIG_IGN && dsc.fun ) {
0275 dsc.fun(signum, info, ptr);
0276 }
0277 else if ( hdlr == SIG_DFL ) {
0278 ::_exit(128+signum);
0279 }
0280 }
0281 s_exit_handler_active = false;
0282 }
0283
0284
0285 SignalHandler::SignalHandler()
0286 {
0287 }
0288
0289
0290 SignalHandler::~SignalHandler() {
0291 }
0292
0293
0294 void SignalHandler::applyHandlers() {
0295 auto& imp = implementation::instance();
0296 struct sigaction old_action { };
0297 printout(INFO, "SignalHandler", "++ Re-apply signal handlers");
0298 for( const auto& e : imp.m_map ) {
0299 ::sigaction (e.first, &e.second.handler_action, &old_action);
0300 printout(DEBUG, "SignalHandler",
0301 "++ Re-apply signal handler for %-10s [%3ld entries]",
0302 e.second.name.c_str(), e.second.user_handlers.size());
0303 }
0304 }
0305
0306
0307 bool SignalHandler::registerHandler(int sig_num, void* param, signal_handler_t handler) {
0308 return implementation::instance().subscribe(sig_num, param, handler) == 1;
0309 }