Gaudi Framework, version v23r2

Home   Generated: Thu Jun 28 2012

SignalMonitorSvc.cpp

Go to the documentation of this file.
00001 /*
00002  * SignalMonitorSvc.cpp
00003  *
00004  *  Created on: Apr 14, 2010
00005  *      Author: Marco Clemencic
00006  */
00007 #include "GaudiKernel/Service.h"
00008 #include "GaudiUtils/ISignalMonitor.h"
00009 
00010 #include <csignal>
00011 
00012 #include <iostream>
00013 
00014 namespace Gaudi {
00015   namespace Utils {
00026     class SignalMonitorSvc: public extends1<Service, Gaudi::ISignalMonitor> {
00027     public:
00028 #ifdef _WIN32
00029       typedef void (__cdecl *handler_t)(int);
00030 #else
00031       typedef struct sigaction handler_t;
00032 #endif
00033 
00036       void monitorSignal(int signum, bool propagate) {
00037         if (!m_monitored[signum]) {
00038           handler_t sa;
00039           handler_t oldact;
00040 #ifdef _WIN32
00041           sa = SignalMonitorSvc::dispatcher;
00042           oldact = signal(signum, sa);
00043 #else
00044           sa.sa_handler = SignalMonitorSvc::dispatcher;
00045           sigemptyset(&sa.sa_mask);
00046           sa.sa_flags = 0;
00047           sigaction(signum, &sa, &oldact);
00048 #endif
00049           m_oldActions[signum] = oldact;
00050           m_monitored[signum] = (propagate) ? SignalMonitorSvc::propagate
00051                                             : SignalMonitorSvc::trap;
00052         }
00053       }
00054 
00057       void ignoreSignal(int signum) {
00058         if (m_monitored[signum]) {
00059 #ifdef _WIN32
00060           (void) signal(signum, m_oldActions[signum]);
00061 #else
00062           sigaction(signum, &m_oldActions[signum], 0);
00063 #endif
00064           m_oldActions[signum] = m_defaultAction;
00065           m_monitored[signum] = ignored;
00066         }
00067       }
00068 
00070       bool gotSignal(int signum) const {
00071         return m_caught[signum] != 0;
00072       }
00073 
00075       void setSignal(int signum) {
00076         m_caught[signum] = 1;
00077       }
00078 
00080       void clearSignal(int signum) {
00081         m_caught[signum] = 0;
00082       }
00083 
00085       SignalMonitorSvc(const std::string& name, ISvcLocator* svcLoc): base_class(name, svcLoc) {
00086 #ifdef _WIN32
00087         m_defaultAction = SIG_DFL;
00088 #else
00089         m_defaultAction.sa_handler = SIG_DFL;
00090         sigemptyset(&m_defaultAction.sa_mask);
00091         m_defaultAction.sa_flags = 0;
00092 #endif
00093         for(int i = 0; i < NSIG; ++i){
00094           m_caught[i] = 0;
00095           m_monitored[i] = ignored;
00096           m_oldActions[i] = m_defaultAction;
00097         }
00098 
00099         setInstance(this);
00100       }
00101 
00103       virtual ~SignalMonitorSvc() {
00104         for (int i = 0; i < NSIG; ++i) {
00105           ignoreSignal(i);
00106         }
00107         setInstance(0);
00108       }
00109 
00110     private:
00112       enum MonitoringMode {
00113         ignored,  //< the signal is not monitored
00114         trap,     //< the signal is monitored and not propagated to previously registered handlers
00115         propagate //< the signal is monitored and propagated to previously registered handlers
00116       };
00118       MonitoringMode   m_monitored[NSIG];
00120       sig_atomic_t     m_caught[NSIG];
00122       handler_t        m_defaultAction;
00124       handler_t        m_oldActions[NSIG];
00125 
00126       void i_handle(int signum) {
00127         m_caught[signum] = 1;
00128         if ( m_monitored[signum] == propagate &&
00129 #ifdef _WIN32
00130             m_oldActions[signum] != SIG_DFL
00131 #else
00132             m_oldActions[signum].sa_handler != SIG_DFL
00133 #endif
00134         ) {
00135 #ifdef _WIN32
00136           m_oldActions[signum](signum);
00137 #else
00138           m_oldActions[signum].sa_handler(signum);
00139 #endif
00140         }
00141       }
00142 
00144       static SignalMonitorSvc *s_instance;
00145 
00146       static inline void setInstance(SignalMonitorSvc *i) {
00147         s_instance = i;
00148       }
00149 
00152       static inline SignalMonitorSvc *instance() {
00153         return s_instance;
00154       }
00155 
00157       static void dispatcher(int signum);
00158     };
00159 
00160     // Implementation of the signal handler function.
00161     void SignalMonitorSvc::dispatcher(int signum){
00162       if (instance()) instance()->i_handle(signum);
00163     }
00164 
00165   } // namespace Utils
00166 } // namespace Gaudi
00167 
00168 #include <cctype>
00169 #include <sstream>
00170 
00171 #include <map>
00172 
00173 #include "GaudiKernel/HashMap.h"
00174 
00175 #include "GaudiKernel/IIncidentListener.h"
00176 #include "GaudiKernel/IIncidentSvc.h"
00177 #include "GaudiKernel/IEventProcessor.h"
00178 #include "GaudiKernel/AppReturnCode.h"
00179 
00180 namespace {
00181   // hack because windows doesn't provide sys_siglist
00182   const char *sig_desc(int signum) {
00183     if (signum >= NSIG || signum < 0)
00184       return 0;
00185 #ifdef _WIN32
00186     switch (signum) {
00187     case SIGINT:   return "Interrupt";
00188     case SIGILL:   return "Illegal instruction";
00189     case SIGFPE:   return "Floating point exception";
00190     case SIGSEGV:  return "Segmentation fault";
00191     case SIGTERM:  return "Terminated";
00192     case SIGBREAK: return "Trace/breakpoint trap";
00193     case SIGABRT:  return "Aborted";
00194     default: return 0;
00195     }
00196 #else
00197     return sys_siglist[signum];
00198 #endif
00199   }
00200 
00202   class SigMap {
00203   public:
00205     static const SigMap& instance() {
00206       static SigMap _instance;
00207       return _instance;
00208     }
00210     inline const std::string &name(int signum) const {
00211       return m_num2id[signum];
00212     }
00214     inline const std::string &desc(int signum) const {
00215       return m_num2desc[signum];
00216     }
00218     inline int signum(const std::string &str) const {
00219       GaudiUtils::HashMap<std::string, int>::const_iterator it;
00220       it = m_name2num.find(str);
00221       if (it == m_name2num.end()) {
00222         return -1;
00223       }
00224       return it->second;
00225     }
00226   private:
00229     SigMap(){
00230 #define addSignal(id) i_addSignal(id, #id);
00231       // List of signals from http://en.wikipedia.org/wiki/POSIX_signal
00232 #ifdef SIGABRT
00233       addSignal(SIGABRT); // Process aborted
00234 #endif
00235 #ifdef SIGALRM
00236       addSignal(SIGALRM); // Signal raised by alarm
00237 #endif
00238 #ifdef SIGBUS
00239       addSignal(SIGBUS); // Bus error: "access to undefined portion of memory object"
00240 #endif
00241 #ifdef SIGCHLD
00242       addSignal(SIGCHLD); // Child process terminated, stopped (or continued*)
00243 #endif
00244 #ifdef SIGCONT
00245       addSignal(SIGCONT); // Continue if stopped
00246 #endif
00247 #ifdef SIGFPE
00248       addSignal(SIGFPE); // Floating point exception: "erroneous arithmetic operation"
00249 #endif
00250 #ifdef SIGHUP
00251       addSignal(SIGHUP); // Hangup
00252 #endif
00253 #ifdef SIGILL
00254       addSignal(SIGILL); // Illegal instruction
00255 #endif
00256 #ifdef SIGINT
00257       addSignal(SIGINT); // Interrupt
00258 #endif
00259 #ifdef SIGKILL
00260       addSignal(SIGKILL); // Kill (terminate immediately)
00261 #endif
00262 #ifdef SIGPIPE
00263       addSignal(SIGPIPE); // Write to pipe with no one reading
00264 #endif
00265 #ifdef SIGQUIT
00266       addSignal(SIGQUIT); // Quit and dump core
00267 #endif
00268 #ifdef SIGSEGV
00269       addSignal(SIGSEGV); // Segmentation violation
00270 #endif
00271 #ifdef SIGSTOP
00272       addSignal(SIGSTOP); // Stop executing temporarily
00273 #endif
00274 #ifdef SIGTERM
00275       addSignal(SIGTERM); // Termination (request to terminate)
00276 #endif
00277 #ifdef SIGTSTP
00278       addSignal(SIGTSTP); // Terminal stop signal
00279 #endif
00280 #ifdef SIGTTIN
00281       addSignal(SIGTTIN); // Background process attempting to read from tty ("in")
00282 #endif
00283 #ifdef SIGTTOU
00284       addSignal(SIGTTOU); // Background process attempting to write to tty ("out")
00285 #endif
00286 #ifdef SIGUSR1
00287       addSignal(SIGUSR1); // User-defined 1
00288 #endif
00289 #ifdef SIGUSR2
00290       addSignal(SIGUSR2); // User-defined 2
00291 #endif
00292 #ifdef SIGPOLL
00293       addSignal(SIGPOLL); // Pollable event
00294 #endif
00295 #ifdef SIGPROF
00296       addSignal(SIGPROF); // Profiling timer expired
00297 #endif
00298 #ifdef SIGSYS
00299       addSignal(SIGSYS); // Bad syscall
00300 #endif
00301 #ifdef SIGTRAP
00302       addSignal(SIGTRAP); // Trace/breakpoint trap
00303 #endif
00304 #ifdef SIGURG
00305       addSignal(SIGURG); // Urgent data available on socket
00306 #endif
00307 #ifdef SIGVTALRM
00308       addSignal(SIGVTALRM); // Signal raised by timer counting virtual time: "virtual timer expired"
00309 #endif
00310 #ifdef SIGXCPU
00311       addSignal(SIGXCPU); // CPU time limit exceeded
00312 #endif
00313 #ifdef SIGXFSZ
00314       addSignal(SIGXFSZ); // File size limit exceeded
00315 #endif
00316 #undef addSignal
00317     }
00319     inline void i_addSignal(int signum, const char *signame) {
00320       m_num2id[signum] = signame;
00321       m_name2num[signame] = signum;
00322       const char* desc = sig_desc(signum);
00323       if (desc) {
00324         m_num2desc[signum] = desc;
00325         m_name2num[desc] = signum;
00326       }
00327     }
00328     GaudiUtils::HashMap<std::string, int> m_name2num; //< Map signal string id or description to number
00329     GaudiUtils::HashMap<int, std::string> m_num2id; //< Map signal number to string id
00330     GaudiUtils::HashMap<int, std::string> m_num2desc; //< Map signal number to description
00331   };
00332 }
00333 
00334 namespace Gaudi {
00335   namespace Utils {
00345     class StopSignalHandler: public extends1<Service, IIncidentListener> {
00346     public:
00347       StopSignalHandler(const std::string& name, ISvcLocator* svcLoc): base_class(name, svcLoc) {
00348         m_usedSignals.reserve(2);
00349         m_usedSignals.push_back("SIGINT");
00350         m_usedSignals.push_back("SIGXCPU");
00351         declareProperty("Signals", m_usedSignals,
00352             "List of signal names or numbers to use to schedule a stop. "
00353             "If the signal is followed by a '+' the signal is propagated the previously "
00354             "registered handler (if any).");
00355       }
00356       StatusCode initialize() {
00357         StatusCode sc = Service::initialize();
00358         if (sc.isFailure()) {
00359           return sc;
00360         }
00361         std::string serviceName("Gaudi::Utils::SignalMonitorSvc");
00362         m_signalMonitor = serviceLocator()->service(serviceName);
00363         if ( ! m_signalMonitor ) {
00364           error() << "Cannot retrieve " << serviceName << endmsg;
00365           return StatusCode::FAILURE;
00366         }
00367         serviceName = "IncidentSvc";
00368         m_incidentSvc = serviceLocator()->service(serviceName);
00369         if ( ! m_incidentSvc ) {
00370           error() << "Cannot retrieve " << serviceName << endmsg;
00371           return StatusCode::FAILURE;
00372         }
00373         // Get the IMainAppStatus interface of the ApplicationMgr
00374         m_appProperty = serviceLocator();
00375         if ( ! m_appProperty ) {
00376           warning() << "Cannot retrieve IProperty interface of ApplicationMgr, "
00377                        "the return code will not be changed" << endmsg;
00378         }
00379         // Decode the signal names
00380         std::pair<int, bool> sigid;
00381         for (std::vector<std::string>::const_iterator signame = m_usedSignals.begin();
00382             signame != m_usedSignals.end(); ++signame) {
00383           sigid = i_decodeSignal(*signame);
00384           if (sigid.first >= 0) {
00385             m_signals[sigid.first] = sigid.second;
00386           }
00387         }
00388         debug() << "Stopping on the signals:" << endmsg;
00389         const SigMap& sigmap(SigMap::instance());
00390         for (std::map<int, bool>::const_iterator s = m_signals.begin();
00391             s != m_signals.end(); ++s) {
00392           debug() << "\t" << sigmap.name(s->first) << ": "
00393                   << sigmap.desc(s->first) << " (" << s->first << ")";
00394           if (s->second) debug() << " propagated";
00395           debug() << endmsg;
00396           // tell the signal monitor that we are interested in these signals
00397           m_signalMonitor->monitorSignal(s->first, s->second);
00398         }
00399         m_stopRequested = false;
00400         debug() << "Register to the IncidentSvc" << endmsg;
00401         m_incidentSvc->addListener(this, IncidentType::BeginEvent);
00402         return StatusCode::SUCCESS;
00403       }
00404       StatusCode finalize() {
00405         m_incidentSvc->removeListener(this, IncidentType::BeginEvent);
00406         m_incidentSvc.reset();
00407         // disable the monitoring of the signals
00408         for (std::map<int, bool>::const_iterator s = m_signals.begin();
00409             s != m_signals.end(); ++s) {
00410           // tell the signal monitor that we are interested in these signals
00411           m_signalMonitor->ignoreSignal(s->first);
00412         }
00413         m_signalMonitor.reset();
00414         return Service::finalize();
00415       }
00416 
00417       virtual void handle(const Incident&) {
00418         if (!m_stopRequested) {
00419           const SigMap& sigmap(SigMap::instance());
00420           for (std::map<int, bool>::const_iterator s = m_signals.begin();
00421               s != m_signals.end(); ++s) {
00422             if (m_signalMonitor->gotSignal(s->first)) {
00423               warning() << "Received signal '" << sigmap.name(s->first)
00424                         << "' (" << s->first;
00425               const std::string &desc = sigmap.desc(s->first);
00426               if ( ! desc.empty() ) {
00427                 warning() << ", " << desc;
00428               }
00429               warning() << ")" << endmsg;
00430               m_stopRequested = true;
00431               // Report the termination by signal at the end of the application
00432               using Gaudi::ReturnCode::SignalOffset;
00433               if (Gaudi::setAppReturnCode(m_appProperty, SignalOffset + s->first).isFailure()) {
00434                 error() << "Could not set return code of the application ("
00435                     << SignalOffset + s->first << ")"
00436                     << endmsg;
00437               }
00438             }
00439           }
00440           if (m_stopRequested) {
00441             SmartIF<IEventProcessor> ep(serviceLocator());
00442             if (ep) {
00443               warning() << "Scheduling a stop" << endmsg;
00444               ep->stopRun().ignore();
00445             }
00446             else {
00447               warning() << "Cannot stop the processing because the IEventProcessor interface cannot be retrieved." << endmsg;
00448             }
00449           }
00450         }
00451       }
00452       private:
00454       std::vector<std::string> m_usedSignals;
00456       std::map<int, bool> m_signals;
00458       bool m_stopRequested;
00460       SmartIF<Gaudi::ISignalMonitor> m_signalMonitor;
00462       SmartIF<IIncidentSvc> m_incidentSvc;
00464       SmartIF<IProperty> m_appProperty;
00466       std::pair<int, bool> i_decodeSignal(const std::string &sig) {
00467         debug() << "Decoding signal declaration '" << sig << "'" << endmsg;
00468         if ( sig.empty() || sig == "+" ) {
00469           debug() << "Empty signal, ignored" << endmsg;
00470           return std::make_pair<int, bool>(-1, false); // silently ignore empty strings
00471         }
00472         const SigMap& sigmap(SigMap::instance());
00473         std::string signal = sig;
00474         bool propagate = false;
00475         // Check if the signal must be propagated
00476         if (signal[signal.size() - 1] == '+') {
00477           debug() << "Must be propagated to previously registered signal handlers" << endmsg;
00478           propagate = true;
00479           signal.erase(signal.size() - 1, 1); // remove the '+' at the end of the string
00480         }
00481         int signum = -1;
00482         // check if the signal is a number
00483         if (std::isdigit(signal[0])){
00484           std::istringstream ss(signal);
00485           ss >> signum;
00486         } else {
00487           // try to find the signal name in the list of known signals
00488           signum = sigmap.signum(signal);
00489         }
00490         if (signum < 0) {
00491           warning() << "Cannot understand signal identifier '" << sig << "', ignored" << endmsg;
00492         } else {
00493           verbose() << "Matched signal '" << sigmap.name(signum)
00494                     << "' (" << signum;
00495           const std::string &desc = sigmap.desc(signum);
00496           if ( ! desc.empty() ) {
00497             verbose() << ", " << desc;
00498           }
00499           verbose() << ")" << endmsg;
00500         }
00501         return std::make_pair(signum, propagate);
00502       }
00503     };
00504 
00505   } // namespace Utils
00506 } // namespace Gaudi
00507 
00508 // Initialization of static data member
00509 Gaudi::Utils::SignalMonitorSvc* Gaudi::Utils::SignalMonitorSvc::s_instance = 0;
00510 
00511 // ========================================================================
00512 #include "GaudiKernel/SvcFactory.h"
00513 
00514 // Instantiation of a static factory class used by clients to create instances of this service
00515 typedef Gaudi::Utils::SignalMonitorSvc g_u_sms;
00516 DECLARE_SERVICE_FACTORY(g_u_sms)
00517 
00518 // Instantiation of a static factory class used by clients to create instances of this service
00519 typedef Gaudi::Utils::StopSignalHandler g_u_ssh;
00520 DECLARE_SERVICE_FACTORY(g_u_ssh)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Thu Jun 28 2012 23:27:29 for Gaudi Framework, version v23r2 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004