Gaudi Framework, version v23r5

Home   Generated: Wed Nov 28 2012
 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  declareProperty("Signals", m_usedSignals,
352  "List of signal names or numbers to use to schedule a stop. "
353  "If the signal is followed by a '+' the signal is propagated the previously "
354  "registered handler (if any).");
355  }
358  if (sc.isFailure()) {
359  return sc;
360  }
361  std::string serviceName("Gaudi::Utils::SignalMonitorSvc");
362  m_signalMonitor = serviceLocator()->service(serviceName);
363  if ( ! m_signalMonitor ) {
364  error() << "Cannot retrieve " << serviceName << endmsg;
365  return StatusCode::FAILURE;
366  }
367  serviceName = "IncidentSvc";
368  m_incidentSvc = serviceLocator()->service(serviceName);
369  if ( ! m_incidentSvc ) {
370  error() << "Cannot retrieve " << serviceName << endmsg;
371  return StatusCode::FAILURE;
372  }
373  // Get the IMainAppStatus interface of the ApplicationMgr
375  if ( ! m_appProperty ) {
376  warning() << "Cannot retrieve IProperty interface of ApplicationMgr, "
377  "the return code will not be changed" << endmsg;
378  }
379  // Decode the signal names
380  std::pair<int, bool> sigid;
382  signame != m_usedSignals.end(); ++signame) {
383  sigid = i_decodeSignal(*signame);
384  if (sigid.first >= 0) {
385  m_signals[sigid.first] = sigid.second;
386  }
387  }
388  debug() << "Stopping on the signals:" << endmsg;
389  const SigMap& sigmap(SigMap::instance());
391  s != m_signals.end(); ++s) {
392  debug() << "\t" << sigmap.name(s->first) << ": "
393  << sigmap.desc(s->first) << " (" << s->first << ")";
394  if (s->second) debug() << " propagated";
395  debug() << endmsg;
396  // tell the signal monitor that we are interested in these signals
397  m_signalMonitor->monitorSignal(s->first, s->second);
398  }
399  m_stopRequested = false;
400  debug() << "Register to the IncidentSvc" << endmsg;
401  m_incidentSvc->addListener(this, IncidentType::BeginEvent);
402  return StatusCode::SUCCESS;
403  }
405  m_incidentSvc->removeListener(this, IncidentType::BeginEvent);
407  // disable the monitoring of the signals
409  s != m_signals.end(); ++s) {
410  // tell the signal monitor that we are interested in these signals
411  m_signalMonitor->ignoreSignal(s->first);
412  }
414  return Service::finalize();
415  }
416 
417  virtual void handle(const Incident&) {
418  if (!m_stopRequested) {
419  const SigMap& sigmap(SigMap::instance());
421  s != m_signals.end(); ++s) {
422  if (m_signalMonitor->gotSignal(s->first)) {
423  warning() << "Received signal '" << sigmap.name(s->first)
424  << "' (" << s->first;
425  const std::string &desc = sigmap.desc(s->first);
426  if ( ! desc.empty() ) {
427  warning() << ", " << desc;
428  }
429  warning() << ")" << endmsg;
430  m_stopRequested = true;
431  // Report the termination by signal at the end of the application
434  error() << "Could not set return code of the application ("
435  << SignalOffset + s->first << ")"
436  << endmsg;
437  }
438  }
439  }
440  if (m_stopRequested) {
442  if (ep) {
443  warning() << "Scheduling a stop" << endmsg;
444  ep->stopRun().ignore();
445  }
446  else {
447  warning() << "Cannot stop the processing because the IEventProcessor interface cannot be retrieved." << endmsg;
448  }
449  }
450  }
451  }
452  private:
467  debug() << "Decoding signal declaration '" << sig << "'" << endmsg;
468  if ( sig.empty() || sig == "+" ) {
469  debug() << "Empty signal, ignored" << endmsg;
470  return std::make_pair<int, bool>(-1, false); // silently ignore empty strings
471  }
472  const SigMap& sigmap(SigMap::instance());
473  std::string signal = sig;
474  bool propagate = false;
475  // Check if the signal must be propagated
476  if (signal[signal.size() - 1] == '+') {
477  debug() << "Must be propagated to previously registered signal handlers" << endmsg;
478  propagate = true;
479  signal.erase(signal.size() - 1, 1); // remove the '+' at the end of the string
480  }
481  int signum = -1;
482  // check if the signal is a number
483  if (std::isdigit(signal[0])){
484  std::istringstream ss(signal);
485  ss >> signum;
486  } else {
487  // try to find the signal name in the list of known signals
488  signum = sigmap.signum(signal);
489  }
490  if (signum < 0) {
491  warning() << "Cannot understand signal identifier '" << sig << "', ignored" << endmsg;
492  } else {
493  verbose() << "Matched signal '" << sigmap.name(signum)
494  << "' (" << signum;
495  const std::string &desc = sigmap.desc(signum);
496  if ( ! desc.empty() ) {
497  verbose() << ", " << desc;
498  }
499  verbose() << ")" << endmsg;
500  }
501  return std::make_pair(signum, propagate);
502  }
503  };
504 
505  } // namespace Utils
506 } // namespace Gaudi
507 
508 // Initialization of static data member
509 Gaudi::Utils::SignalMonitorSvc* Gaudi::Utils::SignalMonitorSvc::s_instance = 0;
510 
511 // ========================================================================
512 #include "GaudiKernel/SvcFactory.h"
513 
514 // Instantiation of a static factory class used by clients to create instances of this service
515 typedef Gaudi::Utils::SignalMonitorSvc g_u_sms;
517 
518 // Instantiation of a static factory class used by clients to create instances of this service
519 typedef Gaudi::Utils::StopSignalHandler g_u_ssh;

Generated at Wed Nov 28 2012 12:17:18 for Gaudi Framework, version v23r5 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004