Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-19 08:31:49

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 
0014 // Framework include files
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 /**@class SignalHandler::implementation
0045  *
0046  * Small class to manipulate default signal handling
0047  *
0048  * \author M.Frank
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   /// Default constructor
0069   implementation();
0070   /// Default destructor
0071   ~implementation();
0072   /// Singleton accessor
0073   static implementation& instance();
0074   /// Initialize the exit handler. Subscribe to default signals
0075   void init();
0076   /// Install handler for a single signal
0077   void install(int num, const std::string& name, struct sigaction& action);
0078   /// Subscribe to a given signal with a user context and a user handler. The context MUST be unique!
0079   int subscribe(int signum, void* user_context, signal_handler_t handler);
0080   /// Unsubscribe from a given signal with a user context identifier
0081   int unsubscribe(int signum, void* user_context);
0082   /// Create simple backtrace
0083   void back_trace(int /* signum */);
0084   /// Static handler callback for system signal handler
0085   static void handler(int signum, siginfo_t *info,void * );
0086 };
0087 
0088 /// Default constructor
0089 SignalHandler::implementation::implementation()  {
0090 }
0091 
0092 /// Default destructor
0093 SignalHandler::implementation::~implementation()  {
0094 }
0095 
0096 /// Singleton accessor
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 /// Initialize the exit handler. Subscribe to default signals
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 /// Subscribe to a given signal with a user context and a user handler. The context MUST be unique!
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() )   { // Should always be true
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 /// Unsubscribe from a given signal with a user context identifier
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 /// Create simple backtrace
0170 void SignalHandler::implementation::back_trace(int /* signum */) {
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 /// Install handler for a single signal
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 /// Static handler callback for system signal handler
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         // Debugging hack, if enabled (default: NO)
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             // Otherwise continue signal processing and eventually call default handlers
0249           }
0250           // No handler fired: call previously registered signal handler
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 /// Default constructor
0285 SignalHandler::SignalHandler()
0286 {
0287 }
0288 
0289 /// Default destructor
0290 SignalHandler::~SignalHandler()  {
0291 }
0292 
0293 /// (Re-)apply registered interrupt handlers to override potentially later registrations by other libraries
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 /// Install handler for any signal
0307 bool SignalHandler::registerHandler(int sig_num, void* param, signal_handler_t handler)  {
0308   return implementation::instance().subscribe(sig_num, param, handler) == 1;
0309 }