Gaudi Framework, version v24r2

Home   Generated: Wed Dec 4 2013
 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"
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;
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:
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  };
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 
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 
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 {
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) {
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  }
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
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;
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());
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  }
406  m_incidentSvc->removeListener(this, IncidentType::BeginEvent);
408  // disable the monitoring of the signals
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  }
415  return Service::finalize();
416  }
417 
418  virtual void handle(const Incident&) {
419  if (!m_stopRequested) {
420  const SigMap& sigmap(SigMap::instance());
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
435  error() << "Could not set return code of the application ("
436  << SignalOffset + s->first << ")"
437  << endmsg;
438  }
439  }
440  }
441  if (m_stopRequested) {
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:
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 #include "GaudiKernel/SvcFactory.h"
514 
515 // Instantiation of a static factory class used by clients to create instances of this service
516 typedef Gaudi::Utils::SignalMonitorSvc g_u_sms;
518 
519 // Instantiation of a static factory class used by clients to create instances of this service
520 typedef Gaudi::Utils::StopSignalHandler g_u_ssh;

Generated at Wed Dec 4 2013 14:33:11 for Gaudi Framework, version v24r2 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004