| # Gaudi Framework, version v25r0 |

Home |  | Generated: Mon Feb 17 2014

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SignalMonitorSvc.cpp
Go to the documentation of this file.
1 /*
2 * SignalMonitorSvc.cpp
3 *
4 * Created on: Apr 14, 2010
5 * Author: Marco Clemencic
6 */
7 #include "GaudiKernel/Service.h"
8 #include "GaudiUtils/ISignalMonitor.h"
9
10 #include <csignal>
11
12 #include <iostream>
13
14 namespace Gaudi {
15 namespace Utils {
26 class SignalMonitorSvc: public extends1<Service, Gaudi::ISignalMonitor> {
27 public:
28 #ifdef _WIN32
29 typedef void (__cdecl *handler_t)(int);
30 #else
31 typedef struct sigaction handler_t;
32 #endif
33
36 void monitorSignal(int signum, bool propagate) {
37 if (!m_monitored[signum]) {
38 handler_t sa;
39 handler_t oldact;
40 #ifdef _WIN32
41 sa = SignalMonitorSvc::dispatcher;
42 oldact = signal(signum, sa);
43 #else
44 sa.sa_handler = SignalMonitorSvc::dispatcher;
45 sigemptyset(&sa.sa_mask);
46 sa.sa_flags = 0;
47 sigaction(signum, &sa, &oldact);
48 #endif
49 m_oldActions[signum] = oldact;
50 m_monitored[signum] = (propagate) ? SignalMonitorSvc::propagate
51 : SignalMonitorSvc::trap;
52 }
53 }
54
57 void ignoreSignal(int signum) {
58 if (m_monitored[signum]) {
59 #ifdef _WIN32
60 (void) signal(signum, m_oldActions[signum]);
61 #else
62 sigaction(signum, &m_oldActions[signum], 0);
63 #endif
64 m_oldActions[signum] = m_defaultAction;
65 m_monitored[signum] = ignored;
66 }
67 }
68
70 bool gotSignal(int signum) const {
71 return m_caught[signum] != 0;
72 }
73
75 void setSignal(int signum) {
76 m_caught[signum] = 1;
77 }
78
80 void clearSignal(int signum) {
81 m_caught[signum] = 0;
82 }
83
85 SignalMonitorSvc(const std::string& name, ISvcLocator* svcLoc): base_class(name, svcLoc) {
86 #ifdef _WIN32
87 m_defaultAction = SIG_DFL;
88 #else
89 m_defaultAction.sa_handler = SIG_DFL;
90 sigemptyset(&m_defaultAction.sa_mask);
91 m_defaultAction.sa_flags = 0;
92 #endif
93 for(int i = 0; i < NSIG; ++i){
94 m_caught[i] = 0;
95 m_monitored[i] = ignored;
96 m_oldActions[i] = m_defaultAction;
97 }
98
99 setInstance(this);
100 }
101
103 virtual ~SignalMonitorSvc() {
104 for (int i = 0; i < NSIG; ++i) {
105 ignoreSignal(i);
106 }
107 setInstance(0);
108 }
109
110 private:
112 enum MonitoringMode {
113 ignored, //< the signal is not monitored
114 trap, //< the signal is monitored and not propagated to previously registered handlers
115 propagate //< the signal is monitored and propagated to previously registered handlers
116 };
118 MonitoringMode m_monitored[NSIG];
120 sig_atomic_t m_caught[NSIG];
122 handler_t m_defaultAction;
124 handler_t m_oldActions[NSIG];
125
126 void i_handle(int signum) {
127 m_caught[signum] = 1;
128 if ( m_monitored[signum] == propagate &&
129 #ifdef _WIN32
130 m_oldActions[signum] != SIG_DFL
131 #else
132 m_oldActions[signum].sa_handler != SIG_DFL
133 #endif
134 ) {
135 #ifdef _WIN32
136 m_oldActions[signum](signum);
137 #else
138 m_oldActions[signum].sa_handler(signum);
139 #endif
140 }
141 }
142
144 static SignalMonitorSvc *s_instance;
145
146 static inline void setInstance(SignalMonitorSvc *i) {
147 s_instance = i;
148 }
149
152 static inline SignalMonitorSvc *instance() {
153 return s_instance;
154 }
155
157 static void dispatcher(int signum);
158 };
159
160 // Implementation of the signal handler function.
161 void SignalMonitorSvc::dispatcher(int signum){
162 if (instance()) instance()->i_handle(signum);
163 }
164
165 } // namespace Utils
166 } // namespace Gaudi
167
168 #include <cctype>
169 #include <sstream>
170
171 #include <map>
172
173 #include "GaudiKernel/HashMap.h"
174
175 #include "GaudiKernel/IIncidentListener.h"
176 #include "GaudiKernel/IIncidentSvc.h"
177 #include "GaudiKernel/IEventProcessor.h"
178 #include "GaudiKernel/AppReturnCode.h"
179
180 namespace {
181 // hack because windows doesn't provide sys_siglist
182 const char *sig_desc(int signum) {
183 if (signum >= NSIG || signum < 0)
184 return 0;
185 #ifdef _WIN32
186 switch (signum) {
187 case SIGINT: return "Interrupt";
188 case SIGILL: return "Illegal instruction";
189 case SIGFPE: return "Floating point exception";
190 case SIGSEGV: return "Segmentation fault";
191 case SIGTERM: return "Terminated";
192 case SIGBREAK: return "Trace/breakpoint trap";
193 case SIGABRT: return "Aborted";
194 default: return 0;
195 }
196 #else
197 return sys_siglist[signum];
198 #endif
199 }
200
202 class SigMap {
203 public:
205 static const SigMap& instance() {
206 static SigMap _instance;
207 return _instance;
208 }
210 inline const std::string &name(int signum) const {
211 return m_num2id[signum];
212 }
214 inline const std::string &desc(int signum) const {
215 return m_num2desc[signum];
216 }
218 inline int signum(const std::string &str) const {
219 GaudiUtils::HashMap<std::string, int>::const_iterator it;
220 it = m_name2num.find(str);
221 if (it == m_name2num.end()) {
222 return -1;
223 }
224 return it->second;
225 }
226 private:
229 SigMap(){
230 #define addSignal(id) i_addSignal(id, #id);
231 // List of signals from http://en.wikipedia.org/wiki/POSIX_signal
232 #ifdef SIGABRT
233 addSignal(SIGABRT); // Process aborted
234 #endif
235 #ifdef SIGALRM
236 addSignal(SIGALRM); // Signal raised by alarm
237 #endif
238 #ifdef SIGBUS
239 addSignal(SIGBUS); // Bus error: "access to undefined portion of memory object"
240 #endif
241 #ifdef SIGCHLD
242 addSignal(SIGCHLD); // Child process terminated, stopped (or continued*)
243 #endif
244 #ifdef SIGCONT
245 addSignal(SIGCONT); // Continue if stopped
246 #endif
247 #ifdef SIGFPE
248 addSignal(SIGFPE); // Floating point exception: "erroneous arithmetic operation"
249 #endif
250 #ifdef SIGHUP
251 addSignal(SIGHUP); // Hangup
252 #endif
253 #ifdef SIGILL
254 addSignal(SIGILL); // Illegal instruction
255 #endif
256 #ifdef SIGINT
257 addSignal(SIGINT); // Interrupt
258 #endif
259 #ifdef SIGKILL
260 addSignal(SIGKILL); // Kill (terminate immediately)
261 #endif
262 #ifdef SIGPIPE
263 addSignal(SIGPIPE); // Write to pipe with no one reading
264 #endif
265 #ifdef SIGQUIT
266 addSignal(SIGQUIT); // Quit and dump core
267 #endif
268 #ifdef SIGSEGV
269 addSignal(SIGSEGV); // Segmentation violation
270 #endif
271 #ifdef SIGSTOP
272 addSignal(SIGSTOP); // Stop executing temporarily
273 #endif
274 #ifdef SIGTERM
275 addSignal(SIGTERM); // Termination (request to terminate)
276 #endif
277 #ifdef SIGTSTP
278 addSignal(SIGTSTP); // Terminal stop signal
279 #endif
280 #ifdef SIGTTIN
281 addSignal(SIGTTIN); // Background process attempting to read from tty ("in")
282 #endif
283 #ifdef SIGTTOU
284 addSignal(SIGTTOU); // Background process attempting to write to tty ("out")
285 #endif
286 #ifdef SIGUSR1
287 addSignal(SIGUSR1); // User-defined 1
288 #endif
289 #ifdef SIGUSR2
290 addSignal(SIGUSR2); // User-defined 2
291 #endif
292 #ifdef SIGPOLL
293 addSignal(SIGPOLL); // Pollable event
294 #endif
295 #ifdef SIGPROF
296 addSignal(SIGPROF); // Profiling timer expired
297 #endif
298 #ifdef SIGSYS
299 addSignal(SIGSYS); // Bad syscall
300 #endif
301 #ifdef SIGTRAP
302 addSignal(SIGTRAP); // Trace/breakpoint trap
303 #endif
304 #ifdef SIGURG
305 addSignal(SIGURG); // Urgent data available on socket
306 #endif
307 #ifdef SIGVTALRM
308 addSignal(SIGVTALRM); // Signal raised by timer counting virtual time: "virtual timer expired"
309 #endif
310 #ifdef SIGXCPU
311 addSignal(SIGXCPU); // CPU time limit exceeded
312 #endif
313 #ifdef SIGXFSZ
314 addSignal(SIGXFSZ); // File size limit exceeded
315 #endif
316 #undef addSignal
317 }
319 inline void i_addSignal(int signum, const char *signame) {
320 m_num2id[signum] = signame;
321 m_name2num[signame] = signum;
322 const char* desc = sig_desc(signum);
323 if (desc) {
324 m_num2desc[signum] = desc;
325 m_name2num[desc] = signum;
326 }
327 }
328 GaudiUtils::HashMap<std::string, int> m_name2num; //< Map signal string id or description to number
329 GaudiUtils::HashMap<int, std::string> m_num2id; //< Map signal number to string id
330 GaudiUtils::HashMap<int, std::string> m_num2desc; //< Map signal number to description
331 };
332 }
333
334 namespace Gaudi {
335 namespace Utils {
345 class StopSignalHandler: public extends1<Service, IIncidentListener> {
346 public:
347 StopSignalHandler(const std::string& name, ISvcLocator* svcLoc): base_class(name, svcLoc) {
348 m_usedSignals.reserve(2);
349 m_usedSignals.push_back("SIGINT");
350 m_usedSignals.push_back("SIGXCPU");
351 m_stopRequested = false;
352 declareProperty("Signals", m_usedSignals,
353 "List of signal names or numbers to use to schedule a stop. "
354 "If the signal is followed by a '+' the signal is propagated the previously "
355 "registered handler (if any).");
356 }
357 StatusCode initialize() {
358 StatusCode sc = Service::initialize();
359 if (sc.isFailure()) {
360 return sc;
361 }
362 std::string serviceName("Gaudi::Utils::SignalMonitorSvc");
363 m_signalMonitor = serviceLocator()->service(serviceName);
364 if ( ! m_signalMonitor ) {
365 error() << "Cannot retrieve " << serviceName << endmsg;
366 return StatusCode::FAILURE;
367 }
368 serviceName = "IncidentSvc";
369 m_incidentSvc = serviceLocator()->service(serviceName);
370 if ( ! m_incidentSvc ) {
371 error() << "Cannot retrieve " << serviceName << endmsg;
372 return StatusCode::FAILURE;
373 }
374 // Get the IMainAppStatus interface of the ApplicationMgr
375 m_appProperty = serviceLocator();
376 if ( ! m_appProperty ) {
377 warning() << "Cannot retrieve IProperty interface of ApplicationMgr, "
378 "the return code will not be changed" << endmsg;
379 }
380 // Decode the signal names
381 std::pair<int, bool> sigid;
382 for (std::vector<std::string>::const_iterator signame = m_usedSignals.begin();
383 signame != m_usedSignals.end(); ++signame) {
384 sigid = i_decodeSignal(*signame);
385 if (sigid.first >= 0) {
386 m_signals[sigid.first] = sigid.second;
387 }
388 }
389 debug() << "Stopping on the signals:" << endmsg;
390 const SigMap& sigmap(SigMap::instance());
391 for (std::map<int, bool>::const_iterator s = m_signals.begin();
392 s != m_signals.end(); ++s) {
393 debug() << "\t" << sigmap.name(s->first) << ": "
394 << sigmap.desc(s->first) << " (" << s->first << ")";
395 if (s->second) debug() << " propagated";
396 debug() << endmsg;
397 // tell the signal monitor that we are interested in these signals
398 m_signalMonitor->monitorSignal(s->first, s->second);
399 }
400 m_stopRequested = false;
401 debug() << "Register to the IncidentSvc" << endmsg;
402 m_incidentSvc->addListener(this, IncidentType::BeginEvent);
403 return StatusCode::SUCCESS;
404 }
405 StatusCode finalize() {
406 m_incidentSvc->removeListener(this, IncidentType::BeginEvent);
407 m_incidentSvc.reset();
408 // disable the monitoring of the signals
409 for (std::map<int, bool>::const_iterator s = m_signals.begin();
410 s != m_signals.end(); ++s) {
411 // tell the signal monitor that we are interested in these signals
412 m_signalMonitor->ignoreSignal(s->first);
413 }
414 m_signalMonitor.reset();
415 return Service::finalize();
416 }
417
418 virtual void handle(const Incident&) {
419 if (!m_stopRequested) {
420 const SigMap& sigmap(SigMap::instance());
421 for (std::map<int, bool>::const_iterator s = m_signals.begin();
422 s != m_signals.end(); ++s) {
423 if (m_signalMonitor->gotSignal(s->first)) {
424 warning() << "Received signal '" << sigmap.name(s->first)
425 << "' (" << s->first;
426 const std::string &desc = sigmap.desc(s->first);
427 if ( ! desc.empty() ) {
428 warning() << ", " << desc;
429 }
430 warning() << ")" << endmsg;
431 m_stopRequested = true;
432 // Report the termination by signal at the end of the application
433 using Gaudi::ReturnCode::SignalOffset;
434 if (Gaudi::setAppReturnCode(m_appProperty, SignalOffset + s->first).isFailure()) {
435 error() << "Could not set return code of the application ("
436 << SignalOffset + s->first << ")"
437 << endmsg;
438 }
439 }
440 }
441 if (m_stopRequested) {
442 SmartIF<IEventProcessor> ep(serviceLocator());
443 if (ep) {
444 warning() << "Scheduling a stop" << endmsg;
445 ep->stopRun().ignore();
446 }
447 else {
448 warning() << "Cannot stop the processing because the IEventProcessor interface cannot be retrieved." << endmsg;
449 }
450 }
451 }
452 }
453 private:
455 std::vector<std::string> m_usedSignals;
457 std::map<int, bool> m_signals;
459 bool m_stopRequested;
461 SmartIF<Gaudi::ISignalMonitor> m_signalMonitor;
463 SmartIF<IIncidentSvc> m_incidentSvc;
465 SmartIF<IProperty> m_appProperty;
467 std::pair<int, bool> i_decodeSignal(const std::string &sig) {
468 debug() << "Decoding signal declaration '" << sig << "'" << endmsg;
469 if ( sig.empty() || sig == "+" ) {
470 debug() << "Empty signal, ignored" << endmsg;
471 return std::make_pair<int, bool>(-1, false); // silently ignore empty strings
472 }
473 const SigMap& sigmap(SigMap::instance());
474 std::string signal = sig;
475 bool propagate = false;
476 // Check if the signal must be propagated
477 if (signal[signal.size() - 1] == '+') {
478 debug() << "Must be propagated to previously registered signal handlers" << endmsg;
479 propagate = true;
480 signal.erase(signal.size() - 1, 1); // remove the '+' at the end of the string
481 }
482 int signum = -1;
483 // check if the signal is a number
484 if (std::isdigit(signal[0])){
485 std::istringstream ss(signal);
486 ss >> signum;
487 } else {
488 // try to find the signal name in the list of known signals
489 signum = sigmap.signum(signal);
490 }
491 if (signum < 0) {
492 warning() << "Cannot understand signal identifier '" << sig << "', ignored" << endmsg;
493 } else {
494 verbose() << "Matched signal '" << sigmap.name(signum)
495 << "' (" << signum;
496 const std::string &desc = sigmap.desc(signum);
497 if ( ! desc.empty() ) {
498 verbose() << ", " << desc;
499 }
500 verbose() << ")" << endmsg;
501 }
502 return std::make_pair(signum, propagate);
503 }
504 };
505
506 } // namespace Utils
507 } // namespace Gaudi
508
509 // Initialization of static data member
510 Gaudi::Utils::SignalMonitorSvc* Gaudi::Utils::SignalMonitorSvc::s_instance = 0;
511
512 // ========================================================================
513 // Instantiation of a static factory class used by clients to create instances of this service
514 typedef Gaudi::Utils::SignalMonitorSvc g_u_sms;
515 DECLARE_COMPONENT(g_u_sms)
516
517 // Instantiation of a static factory class used by clients to create instances of this service
518 typedef Gaudi::Utils::StopSignalHandler g_u_ssh;
519 DECLARE_COMPONENT(g_u_ssh)