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
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;
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.
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) {
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  }
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;
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  }
406  m_incidentSvc->removeListener(this, IncidentType::BeginEvent);
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
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:
455  std::vector<std::string> m_usedSignals;
457  std::map<int, bool> m_signals;
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
511 
512 // ========================================================================
513 // Instantiation of a static factory class used by clients to create instances of this service
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)
const std::string BeginEvent
Processing of a new event has started.
Definition: Incident.h:60
sig_atomic_t m_caught[NSIG]
Array of flags for received signals.
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:26
bool m_stopRequested
Flag to remember if the stop has been requested because of a signal.
bool gotSignal(int signum) const
Check if the given signal has been received.
SmartIF< IIncidentSvc > m_incidentSvc
Pointer to the incident service.
void clearSignal(int signum)
Clear the flag for the given signal, so that a new occurrence can be identified.
Gaudi::Utils::SignalMonitorSvc g_u_sms
const int SignalOffset
Definition: AppReturnCode.h:34
void ignoreSignal(int signum)
Remove the specific signal handler for the requested signal, restoring the previous signal handler...
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
static void dispatcher(int signum)
Signal handler function.
StatusCode finalize()
Finalize (from INITIALIZED to CONFIGURED).
SmartIF< Gaudi::ISignalMonitor > m_signalMonitor
Pointer to the signal monitor service.
std::vector< std::string > m_usedSignals
List of signal names or numbers (encoded as strings) to use to schedule a stop.
bool isFailure() const
Test for a status code of FAILURE.
Definition: StatusCode.h:72
#define DECLARE_COMPONENT(type)
Definition: PluginService.h:35
MonitoringMode
Possible monitoring modes.
std::map< int, bool > m_signals
Map of monitored signal numbers to the flag telling if they have to be propagated or not...
static void setInstance(SignalMonitorSvc *i)
iterator end()
Definition: Map.h:131
static SignalMonitorSvc * instance()
Method to get the singleton instance.
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
Implementation of Gaudi::ISignalMonitor.
virtual void handle(const Incident &)
Inform that a new incident has occurred.
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:30
SignalMonitorSvc(const std::string &name, ISvcLocator *svcLoc)
Initialize internal variables of the service and set the instance pointer.
Base class used to extend a class implementing other interfaces.
Definition: extends.h:10
iterator find(const key_type &key)
Definition: Map.h:148
SmartIF< IProperty > m_appProperty
Pointer to the interface to set the return code of the application.
std::pair< int, bool > i_decodeSignal(const std::string &sig)
Function to translate the signal name to the signal number.
void setSignal(int signum)
Set the flag for the given signal, as if the signal was received.
map_type::const_iterator const_iterator
Definition: Map.h:99
Service that stop the processing if a signal is received.
StatusCode setAppReturnCode(SmartIF< IProperty > &appmgr, int value, bool force=false)
Set the application return code.
Definition: AppReturnCode.h:50
virtual const std::string & name() const
Retrieve name of the service.
Definition: Service.cpp:331
static SignalMonitorSvc * s_instance
Pointer to the current instance.
void monitorSignal(int signum, bool propagate)
Declare a signal to be monitored.
virtual StatusCode initialize()
Initialization (from CONFIGURED to INITIALIZED).
Definition: Service.cpp:74
Base class for all Incidents (computing events).
Definition: Incident.h:16
string s
Definition: gaudirun.py:210
Templated class to add the standard messaging functionalities.
#define addSignal(id)
StopSignalHandler(const std::string &name, ISvcLocator *svcLoc)
MonitoringMode m_monitored[NSIG]
Array of flags to keep track of monitored signals.
handler_t m_oldActions[NSIG]
List of replaced signal actions (for the recovery when disable the monitoring).
#define __cdecl
Definition: xtoa.h:2
handler_t m_defaultAction
Helper variable for default signal action.
Property * declareProperty(const std::string &name, T &property, const std::string &doc="none") const
Declare the named property.
Definition: Service.h:209
This is a number of static methods for bootstrapping the Gaudi framework.
Definition: Bootstrap.h:15
virtual ~SignalMonitorSvc()
Stop monitoring signals and clear the instance pointer.
list i
Definition: ana.py:128
StatusCode initialize()
Initialization (from CONFIGURED to INITIALIZED).
Gaudi::Utils::StopSignalHandler g_u_ssh
void reset(TYPE *ptr=0)
Set the internal pointer to the passed one disposing of the old one.
Definition: SmartIF.h:74
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
virtual StatusCode finalize()
Finalize (from INITIALIZED to CONFIGURED).
Definition: Service.cpp:199
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:243
SmartIF< ISvcLocator > & serviceLocator() const
Retrieve pointer to service locator.
Definition: Service.cpp:336