Sierra Toolkit Version of the Day
SignalHandler.cpp
00001 
00010 #include <stdexcept>
00011 #include <vector>
00012 #include <iostream>
00013 
00014 #include <stk_util/diag/SignalHandler.hpp>
00015 
00016 #include <signal.h>
00017 #include <time.h>
00018 
00019 extern "C" {
00020   static void signal_handler(int signal, siginfo_t *sip, void *ucp)
00021   {
00022     // This routine is called for all signals...
00023     // Just a C-callable wrapper around a call to the true signal handler...
00024     sierra::SignalHandler::instance().handle_signal(signal);
00025   }
00026 }
00027 
00028 namespace sierra {
00029 
00030 namespace {
00031 
00032 int
00033 convert_name_to_signal(
00034   const String &  signal)
00035 {
00036   if (signal == "SIGABRT" || signal == "SIGKILL") {
00037     return -1;
00038   }
00039 
00040 #if defined(SIGILL)
00041   if (signal == "SIGILL") return SIGILL;
00042 #endif
00043 #if defined(SIGSEGV)
00044   if (signal == "SIGSEGV") return SIGSEGV;
00045 #endif
00046 #if defined(SIGALRM)
00047   if (signal == "SIGALRM") return SIGALRM;
00048 #endif
00049 #if defined(SIGFPE)
00050   if (signal == "SIGFPE")  return SIGFPE;
00051 #endif
00052 #if defined(SIGHUP)
00053   if (signal == "SIGHUP")  return SIGHUP;
00054 #endif
00055 #if defined(SIGINT)
00056   if (signal == "SIGINT")  return SIGINT;
00057 #endif
00058 #if defined(SIGPIPE)
00059   if (signal == "SIGPIPE") return SIGPIPE;
00060 #endif
00061 #if defined(SIGQUIT)
00062   if (signal == "SIGQUIT") return SIGQUIT;
00063 #endif
00064 #if defined(SIGTERM)
00065   if (signal == "SIGTERM") return SIGTERM;
00066 #endif
00067 #if defined(SIGUSR1)
00068   if (signal == "SIGUSR1") return SIGUSR1;
00069 #endif
00070 #if defined(SIGUSR2)
00071   if (signal == "SIGUSR2") return SIGUSR2;
00072 #endif
00073   return -2;
00074 }
00075 
00076 } // namespace <unnamed>
00077 
00078 
00079 SignalHandler &
00080 SignalHandler::instance() {
00081   static SignalHandler signal_handler;
00082 
00083   return signal_handler;
00084 }
00085 
00086 
00087 void
00088 SignalHandler::handle_signal(
00089   int     signal)
00090 {
00091   typedef std::vector<const HandlerMap::value_type *> HandlerList;
00092 
00093   time_t now = ::time(NULL);
00094 
00095   std::cerr << "Sierra received signal " << signal << " at " << ::ctime(&now) << std::endl;
00096 
00097   HandlerList   handlers;
00098 
00099   std::pair<HandlerMap::const_iterator, HandlerMap::const_iterator> range = m_handlerMap.equal_range(signal);
00100 
00101   for (HandlerMap::const_iterator pos = range.first; pos != range.second; ++pos)
00102     handlers.push_back(&*pos);
00103 
00104   for (HandlerList::const_iterator it = handlers.begin(); it != handlers.end(); ++it) {
00105     CallbackBase &obj = *(*it)->second;
00106     obj();
00107   }
00108 }
00109 
00110 
00111 bool
00112 SignalHandler::check_signal_name(
00113   const String &  signal)
00114 {
00115   int isignal = convert_name_to_signal(signal);
00116   return (isignal >= 0);
00117 }
00118 
00119 
00120 void
00121 SignalHandler::add_handler(
00122   const String &  signal,
00123   CallbackBase &  callback)
00124 {
00125   int isignal = convert_name_to_signal(signal);
00126   if (isignal >= 0) {
00127     add_handler(isignal, callback);
00128   }
00129   else if (isignal == -1)
00130     throw std::runtime_error("signal cannot be handled");
00131   else if (isignal == -2)
00132     throw std::runtime_error("signal name invalid");
00133   else
00134     throw std::logic_error("invalid value from convert_node_to_signal()");
00135 }
00136 
00137 
00138 void
00139 SignalHandler::add_handler(
00140   int     signal,
00141   CallbackBase &  callback)
00142 {
00143   // See if already handling this signal...
00144   if (m_handlerMap.find(signal) == m_handlerMap.end()) {
00145     // Tell OS that we want to handle this signal...
00146     struct sigaction action;
00147     struct sigaction *old_action = new struct sigaction;
00148 
00149     action.sa_sigaction = signal_handler;
00150     sigemptyset(&action.sa_mask);
00151     action.sa_flags = SA_SIGINFO;
00152     ::sigaction(signal, &action, old_action);
00153     m_oldActionMap.insert(OldActionMap::value_type(signal, old_action));
00154   }
00155   m_handlerMap.insert(HandlerMap::value_type(signal, &callback));
00156 }
00157 
00158 
00159 void
00160 SignalHandler::remove_handler(
00161   int     signal,
00162   CallbackBase &  callback)
00163 {
00164   typedef std::pair<HandlerMap::iterator, HandlerMap::iterator> HandlerRange;
00165 
00166   HandlerRange handler_range = m_handlerMap.equal_range(signal);
00167   for (HandlerMap::iterator it = handler_range.first; it != handler_range.second; )
00168     if ((*it).second == &callback) {
00169       HandlerMap::iterator erase_it = it++;
00170       m_handlerMap.erase(erase_it);
00171     }
00172     else
00173       ++it;
00174 
00175   if (m_handlerMap.find(signal) == m_handlerMap.end()) {
00176     OldActionMap::iterator it = m_oldActionMap.find(signal);
00177     if (it != m_oldActionMap.end()) {
00178       ::sigaction(signal, (*it).second, NULL);
00179       delete (*it).second;
00180       m_oldActionMap.erase(it);
00181     }
00182   }
00183 }
00184 
00185 
00186 void
00187 SignalHandler::remove_handler(
00188   const String &  signal,
00189   CallbackBase &  callback)
00190 {
00191   int isignal = convert_name_to_signal(signal);
00192   if (isignal >= 0) {
00193     remove_handler(isignal, callback);
00194   }
00195   else if (isignal == -1)
00196     throw std::runtime_error("signal cannot be handled");
00197   else if (isignal == -2)
00198     throw std::runtime_error("signal name invalid");
00199   else
00200     throw std::logic_error("invalid value from convert_node_to_signal()");
00201 }
00202 
00203 
00204 void
00205 SignalHandler::remove_all_handlers()
00206 {
00207   m_handlerMap.clear();
00208 
00209   for (OldActionMap::iterator it = m_oldActionMap.begin(); it != m_oldActionMap.end(); ++it) {
00210     ::sigaction((*it).first, (*it).second, NULL);
00211     delete (*it).second;
00212   }
00213   m_oldActionMap.clear();
00214 }
00215 
00216 
00217 } // namespace sierra
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines