Go to the documentation of this file.00001
00002
00003
00004
00005
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,
00114 trap,
00115 propagate
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
00161 void SignalMonitorSvc::dispatcher(int signum){
00162 if (instance()) instance()->i_handle(signum);
00163 }
00164
00165 }
00166 }
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
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
00232 #ifdef SIGABRT
00233 addSignal(SIGABRT);
00234 #endif
00235 #ifdef SIGALRM
00236 addSignal(SIGALRM);
00237 #endif
00238 #ifdef SIGBUS
00239 addSignal(SIGBUS);
00240 #endif
00241 #ifdef SIGCHLD
00242 addSignal(SIGCHLD);
00243 #endif
00244 #ifdef SIGCONT
00245 addSignal(SIGCONT);
00246 #endif
00247 #ifdef SIGFPE
00248 addSignal(SIGFPE);
00249 #endif
00250 #ifdef SIGHUP
00251 addSignal(SIGHUP);
00252 #endif
00253 #ifdef SIGILL
00254 addSignal(SIGILL);
00255 #endif
00256 #ifdef SIGINT
00257 addSignal(SIGINT);
00258 #endif
00259 #ifdef SIGKILL
00260 addSignal(SIGKILL);
00261 #endif
00262 #ifdef SIGPIPE
00263 addSignal(SIGPIPE);
00264 #endif
00265 #ifdef SIGQUIT
00266 addSignal(SIGQUIT);
00267 #endif
00268 #ifdef SIGSEGV
00269 addSignal(SIGSEGV);
00270 #endif
00271 #ifdef SIGSTOP
00272 addSignal(SIGSTOP);
00273 #endif
00274 #ifdef SIGTERM
00275 addSignal(SIGTERM);
00276 #endif
00277 #ifdef SIGTSTP
00278 addSignal(SIGTSTP);
00279 #endif
00280 #ifdef SIGTTIN
00281 addSignal(SIGTTIN);
00282 #endif
00283 #ifdef SIGTTOU
00284 addSignal(SIGTTOU);
00285 #endif
00286 #ifdef SIGUSR1
00287 addSignal(SIGUSR1);
00288 #endif
00289 #ifdef SIGUSR2
00290 addSignal(SIGUSR2);
00291 #endif
00292 #ifdef SIGPOLL
00293 addSignal(SIGPOLL);
00294 #endif
00295 #ifdef SIGPROF
00296 addSignal(SIGPROF);
00297 #endif
00298 #ifdef SIGSYS
00299 addSignal(SIGSYS);
00300 #endif
00301 #ifdef SIGTRAP
00302 addSignal(SIGTRAP);
00303 #endif
00304 #ifdef SIGURG
00305 addSignal(SIGURG);
00306 #endif
00307 #ifdef SIGVTALRM
00308 addSignal(SIGVTALRM);
00309 #endif
00310 #ifdef SIGXCPU
00311 addSignal(SIGXCPU);
00312 #endif
00313 #ifdef SIGXFSZ
00314 addSignal(SIGXFSZ);
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;
00329 GaudiUtils::HashMap<int, std::string> m_num2id;
00330 GaudiUtils::HashMap<int, std::string> m_num2desc;
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
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
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
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
00408 for (std::map<int, bool>::const_iterator s = m_signals.begin();
00409 s != m_signals.end(); ++s) {
00410
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
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);
00471 }
00472 const SigMap& sigmap(SigMap::instance());
00473 std::string signal = sig;
00474 bool propagate = false;
00475
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);
00480 }
00481 int signum = -1;
00482
00483 if (std::isdigit(signal[0])){
00484 std::istringstream ss(signal);
00485 ss >> signum;
00486 } else {
00487
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 }
00506 }
00507
00508
00509 Gaudi::Utils::SignalMonitorSvc* Gaudi::Utils::SignalMonitorSvc::s_instance = 0;
00510
00511
00512 #include "GaudiKernel/SvcFactory.h"
00513
00514
00515 typedef Gaudi::Utils::SignalMonitorSvc g_u_sms;
00516 DECLARE_SERVICE_FACTORY(g_u_sms)
00517
00518
00519 typedef Gaudi::Utils::StopSignalHandler g_u_ssh;
00520 DECLARE_SERVICE_FACTORY(g_u_ssh)