| # Gaudi Framework, version v21r10p1 |

Home |  | Generated: 29 Jul 2010

# 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               if (Gaudi::setAppReturnCode(m_appProperty, 128 + s->first).isFailure()) {
    00433                 error() << "Could not set return code of the application ("
    00434                     << 128 + s->first << ")"
    00435                     << endmsg;
    00436               }
    00437               if (m_appProperty) {
    00438                 // Check the current return code (we want to keep the first error)
    00439                 IntegerProperty returnCode("ReturnCode", 0);
    00440                 StatusCode sc = m_appProperty->getProperty(&returnCode);
    00441                 if (sc.isSuccess()) {
    00442                   if (returnCode.value() == 0) {
    00443                     returnCode.setValue(128 + s->first);
    00444                     sc = m_appProperty->setProperty(returnCode);
    00445                   }
    00446                 }
    00447                 if (sc.isFailure()) {
    00448                   error() << "Could not set return code of the application ("
    00449                       << 128 + s->first << ")"
    00450                       << endmsg;
    00451                 }
    00452               }
    00453             }
    00454           }
    00455           if (m_stopRequested) {
    00456             SmartIF<IEventProcessor> ep(serviceLocator());
    00457             if (ep) {
    00458               warning() << "Scheduling a stop" << endmsg;
    00459               ep->stopRun().ignore();
    00460             }
    00461             else {
    00462               warning() << "Cannot stop the processing because the IEventProcessor interface cannot be retrieved." << endmsg;
    00463             }
    00464           }
    00465         }
    00466       }
    00467       private:
    00469       std::vector<std::string> m_usedSignals;
    00471       std::map<int, bool> m_signals;
    00473       bool m_stopRequested;
    00475       SmartIF<Gaudi::ISignalMonitor> m_signalMonitor;
    00477       SmartIF<IIncidentSvc> m_incidentSvc;
    00479       SmartIF<IProperty> m_appProperty;
    00481       std::pair<int, bool> i_decodeSignal(const std::string &sig) {
    00482         debug() << "Decoding signal declaration '" << sig << "'" << endmsg;
    00483         if ( sig.empty() || sig == "+" ) {
    00484           debug() << "Empty signal, ignored" << endmsg;
    00485           return std::make_pair<int, bool>(-1, false); // silently ignore empty strings
    00486         }
    00487         const SigMap& sigmap(SigMap::instance());
    00488         std::string signal = sig;
    00489         bool propagate = false;
    00490         // Check if the signal must be propagated
    00491         if (signal[signal.size() - 1] == '+') {
    00492           debug() << "Must be propagated to previously registered signal handlers" << endmsg;
    00493           propagate = true;
    00494           signal.erase(signal.size() - 1, 1); // remove the '+' at the end of the string
    00495         }
    00496         int signum = -1;
    00497         // check if the signal is a number
    00498         if (std::isdigit(signal[0])){
    00499           std::istringstream ss(signal);
    00500           ss >> signum;
    00501         } else {
    00502           // try to find the signal name in the list of known signals
    00503           signum = sigmap.signum(signal);
    00504         }
    00505         if (signum < 0) {
    00506           warning() << "Cannot understand signal identifier '" << sig << "', ignored" << endmsg;
    00507         } else {
    00508           verbose() << "Matched signal '" << sigmap.name(signum)
    00509                     << "' (" << signum;
    00510           const std::string &desc = sigmap.desc(signum);
    00511           if ( ! desc.empty() ) {
    00512             verbose() << ", " << desc;
    00513           }
    00514           verbose() << ")" << endmsg;
    00515         }
    00516         return std::make_pair<int, bool>(signum, propagate);
    00517       }
    00518     };
    00519
    00520   } // namespace Utils
    00521 } // namespace Gaudi
    00522
    00523 // Initialization of static data member
    00524 Gaudi::Utils::SignalMonitorSvc* Gaudi::Utils::SignalMonitorSvc::s_instance = 0;
    00525
    00526 // ========================================================================
    00527 #include "GaudiKernel/SvcFactory.h"
    00528
    00529 // Instantiation of a static factory class used by clients to create instances of this service
    00530 typedef Gaudi::Utils::SignalMonitorSvc g_u_sms;
    00531 DECLARE_SERVICE_FACTORY(g_u_sms)
    00532
    00533 // Instantiation of a static factory class used by clients to create instances of this service
    00534 typedef Gaudi::Utils::StopSignalHandler g_u_ssh;
    00535 DECLARE_SERVICE_FACTORY(g_u_ssh)