Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v31r0 (aeb156f0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules 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 extends<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 ) override {
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;
51  }
52  }
53 
56  void ignoreSignal( int signum ) override {
57  if ( m_monitored[signum] ) {
58 #ifdef _WIN32
59  (void)signal( signum, m_oldActions[signum] );
60 #else
61  sigaction( signum, &m_oldActions[signum], nullptr );
62 #endif
63  m_oldActions[signum] = m_defaultAction;
64  m_monitored[signum] = ignored;
65  }
66  }
67 
69  bool gotSignal( int signum ) const override { return m_caught[signum] != 0; }
70 
72  void setSignal( int signum ) override { m_caught[signum] = 1; }
73 
75  void clearSignal( int signum ) override { m_caught[signum] = 0; }
76 
78  SignalMonitorSvc( const std::string& name, ISvcLocator* svcLoc ) : base_class( name, svcLoc ) {
79 #ifdef _WIN32
80  m_defaultAction = SIG_DFL;
81 #else
82  m_defaultAction.sa_handler = SIG_DFL;
83  sigemptyset( &m_defaultAction.sa_mask );
84  m_defaultAction.sa_flags = 0;
85 #endif
86  for ( int i = 0; i < NSIG; ++i ) {
87  m_caught[i] = 0;
88  m_monitored[i] = ignored;
90  }
91 
92  setInstance( this );
93  }
94 
96  ~SignalMonitorSvc() override {
97  for ( int i = 0; i < NSIG; ++i ) ignoreSignal( i );
98  setInstance( nullptr );
99  }
100 
101  private:
104  ignored, //< the signal is not monitored
105  trap, //< the signal is monitored and not propagated to previously registered handlers
106  propagate //< the signal is monitored and propagated to previously registered handlers
107  };
111  sig_atomic_t m_caught[NSIG];
113  handler_t m_defaultAction;
115  handler_t m_oldActions[NSIG];
116 
117  void i_handle( int signum ) {
118  m_caught[signum] = 1;
119  if ( m_monitored[signum] == propagate &&
120 #ifdef _WIN32
121  m_oldActions[signum] != SIG_DFL
122 #else
123  m_oldActions[signum].sa_handler != SIG_DFL
124 #endif
125  ) {
126 #ifdef _WIN32
127  m_oldActions[signum]( signum );
128 #else
129  m_oldActions[signum].sa_handler( signum );
130 #endif
131  }
132  }
133 
136 
137  static inline void setInstance( SignalMonitorSvc* i ) { s_instance = i; }
138 
141  static inline SignalMonitorSvc* instance() { return s_instance; }
142 
144  static void dispatcher( int signum );
145  };
146 
147  // Implementation of the signal handler function.
148  void SignalMonitorSvc::dispatcher( int signum ) {
149  if ( instance() ) instance()->i_handle( signum );
150  }
151 
152  } // namespace Utils
153 } // namespace Gaudi
154 
155 #include <cctype>
156 #include <sstream>
157 
158 #include <map>
159 
160 #include "GaudiKernel/HashMap.h"
161 
166 
167 namespace {
168  // hack because windows doesn't provide sys_siglist
169  const char* sig_desc( int signum ) {
170  if ( signum >= NSIG || signum < 0 ) return nullptr;
171 #ifdef _WIN32
172  switch ( signum ) {
173  case SIGINT:
174  return "Interrupt";
175  case SIGILL:
176  return "Illegal instruction";
177  case SIGFPE:
178  return "Floating point exception";
179  case SIGSEGV:
180  return "Segmentation fault";
181  case SIGTERM:
182  return "Terminated";
183  case SIGBREAK:
184  return "Trace/breakpoint trap";
185  case SIGABRT:
186  return "Aborted";
187  default:
188  return 0;
189  }
190 #else
191  return sys_siglist[signum];
192 #endif
193  }
194 
196  class SigMap {
197  public:
199  static const SigMap& instance() {
200  static SigMap _instance;
201  return _instance;
202  }
204  inline const std::string& name( int signum ) const { return m_num2id[signum]; }
206  inline const std::string& desc( int signum ) const { return m_num2desc[signum]; }
208  inline int signum( const std::string& str ) const {
209  auto it = m_name2num.find( str );
210  return it != m_name2num.end() ? it->second : -1;
211  }
212 
213  private:
216  SigMap() {
217 #define addSignal( id ) i_addSignal( id, #id );
218 // List of signals from http://en.wikipedia.org/wiki/POSIX_signal
219 #ifdef SIGABRT
220  addSignal( SIGABRT ); // Process aborted
221 #endif
222 #ifdef SIGALRM
223  addSignal( SIGALRM ); // Signal raised by alarm
224 #endif
225 #ifdef SIGBUS
226  addSignal( SIGBUS ); // Bus error: "access to undefined portion of memory object"
227 #endif
228 #ifdef SIGCHLD
229  addSignal( SIGCHLD ); // Child process terminated, stopped (or continued*)
230 #endif
231 #ifdef SIGCONT
232  addSignal( SIGCONT ); // Continue if stopped
233 #endif
234 #ifdef SIGFPE
235  addSignal( SIGFPE ); // Floating point exception: "erroneous arithmetic operation"
236 #endif
237 #ifdef SIGHUP
238  addSignal( SIGHUP ); // Hangup
239 #endif
240 #ifdef SIGILL
241  addSignal( SIGILL ); // Illegal instruction
242 #endif
243 #ifdef SIGINT
244  addSignal( SIGINT ); // Interrupt
245 #endif
246 #ifdef SIGKILL
247  addSignal( SIGKILL ); // Kill (terminate immediately)
248 #endif
249 #ifdef SIGPIPE
250  addSignal( SIGPIPE ); // Write to pipe with no one reading
251 #endif
252 #ifdef SIGQUIT
253  addSignal( SIGQUIT ); // Quit and dump core
254 #endif
255 #ifdef SIGSEGV
256  addSignal( SIGSEGV ); // Segmentation violation
257 #endif
258 #ifdef SIGSTOP
259  addSignal( SIGSTOP ); // Stop executing temporarily
260 #endif
261 #ifdef SIGTERM
262  addSignal( SIGTERM ); // Termination (request to terminate)
263 #endif
264 #ifdef SIGTSTP
265  addSignal( SIGTSTP ); // Terminal stop signal
266 #endif
267 #ifdef SIGTTIN
268  addSignal( SIGTTIN ); // Background process attempting to read from tty ("in")
269 #endif
270 #ifdef SIGTTOU
271  addSignal( SIGTTOU ); // Background process attempting to write to tty ("out")
272 #endif
273 #ifdef SIGUSR1
274  addSignal( SIGUSR1 ); // User-defined 1
275 #endif
276 #ifdef SIGUSR2
277  addSignal( SIGUSR2 ); // User-defined 2
278 #endif
279 #ifdef SIGPOLL
280  addSignal( SIGPOLL ); // Pollable event
281 #endif
282 #ifdef SIGPROF
283  addSignal( SIGPROF ); // Profiling timer expired
284 #endif
285 #ifdef SIGSYS
286  addSignal( SIGSYS ); // Bad syscall
287 #endif
288 #ifdef SIGTRAP
289  addSignal( SIGTRAP ); // Trace/breakpoint trap
290 #endif
291 #ifdef SIGURG
292  addSignal( SIGURG ); // Urgent data available on socket
293 #endif
294 #ifdef SIGVTALRM
295  addSignal( SIGVTALRM ); // Signal raised by timer counting virtual time: "virtual timer expired"
296 #endif
297 #ifdef SIGXCPU
298  addSignal( SIGXCPU ); // CPU time limit exceeded
299 #endif
300 #ifdef SIGXFSZ
301  addSignal( SIGXFSZ ); // File size limit exceeded
302 #endif
303 #undef addSignal
304  }
306  inline void i_addSignal( int signum, const char* signame ) {
307  m_num2id[signum] = signame;
308  m_name2num[signame] = signum;
309  const char* desc = sig_desc( signum );
310  if ( desc ) {
311  m_num2desc[signum] = desc;
312  m_name2num[desc] = signum;
313  }
314  }
315  GaudiUtils::HashMap<std::string, int> m_name2num; //< Map signal string id or description to number
316  GaudiUtils::HashMap<int, std::string> m_num2id; //< Map signal number to string id
317  GaudiUtils::HashMap<int, std::string> m_num2desc; //< Map signal number to description
318  };
319 } // namespace
320 
321 namespace Gaudi {
322  namespace Utils {
332  class StopSignalHandler : public extends<Service, IIncidentListener> {
333  public:
334  using extends::extends;
335  StatusCode initialize() override {
337  if ( sc.isFailure() ) { return sc; }
338  std::string serviceName( "Gaudi::Utils::SignalMonitorSvc" );
339  m_signalMonitor = serviceLocator()->service( serviceName );
340  if ( !m_signalMonitor ) {
341  error() << "Cannot retrieve " << serviceName << endmsg;
342  return StatusCode::FAILURE;
343  }
344  serviceName = "IncidentSvc";
345  m_incidentSvc = serviceLocator()->service( serviceName );
346  if ( !m_incidentSvc ) {
347  error() << "Cannot retrieve " << serviceName << endmsg;
348  return StatusCode::FAILURE;
349  }
350  // Get the IMainAppStatus interface of the ApplicationMgr
351  m_appProperty = serviceLocator();
352  if ( !m_appProperty ) {
353  warning() << "Cannot retrieve IProperty interface of ApplicationMgr, "
354  "the return code will not be changed"
355  << endmsg;
356  }
357  // Decode the signal names
358  for ( const auto& signame : m_usedSignals ) {
359  auto sigid = i_decodeSignal( signame );
360  if ( sigid.first >= 0 ) { m_signals[sigid.first] = sigid.second; }
361  }
362  debug() << "Stopping on the signals:" << endmsg;
363  const SigMap& sigmap( SigMap::instance() );
364  for ( const auto& s : m_signals ) {
365  debug() << "\t" << sigmap.name( s.first ) << ": " << sigmap.desc( s.first ) << " (" << s.first << ")";
366  if ( s.second ) debug() << " propagated";
367  debug() << endmsg;
368  // tell the signal monitor that we are interested in these signals
369  m_signalMonitor->monitorSignal( s.first, s.second );
370  }
371  m_stopRequested = false;
372  debug() << "Register to the IncidentSvc" << endmsg;
373  m_incidentSvc->addListener( this, IncidentType::BeginEvent );
374  return StatusCode::SUCCESS;
375  }
376  StatusCode finalize() override {
377  m_incidentSvc->removeListener( this, IncidentType::BeginEvent );
378  m_incidentSvc.reset();
379  // disable the monitoring of the signals
380  std::for_each( std::begin( m_signals ), std::end( m_signals ), [&]( const std::pair<int, bool>& s ) {
381  // tell the signal monitor that we are interested in these signals
382  m_signalMonitor->ignoreSignal( s.first );
383  } );
384  m_signalMonitor.reset();
385  return Service::finalize();
386  }
387 
388  void handle( const Incident& ) override {
389  if ( !m_stopRequested ) {
390  const SigMap& sigmap( SigMap::instance() );
391  for ( const auto& s : m_signals ) {
392  if ( !m_signalMonitor->gotSignal( s.first ) ) continue;
393  warning() << "Received signal '" << sigmap.name( s.first ) << "' (" << s.first;
394  const std::string& desc = sigmap.desc( s.first );
395  if ( !desc.empty() ) warning() << ", " << desc;
396  warning() << ")" << endmsg;
397  m_stopRequested = true;
398  // Report the termination by signal at the end of the application
400  if ( Gaudi::setAppReturnCode( m_appProperty, SignalOffset + s.first ).isFailure() ) {
401  error() << "Could not set return code of the application (" << SignalOffset + s.first << ")" << endmsg;
402  }
403  }
404  if ( m_stopRequested ) {
405  auto ep = serviceLocator()->as<IEventProcessor>();
406  if ( ep ) {
407  warning() << "Scheduling a stop" << endmsg;
408  ep->stopRun().ignore();
409  } else {
410  warning() << "Cannot stop the processing because the IEventProcessor interface cannot be retrieved."
411  << endmsg;
412  }
413  }
414  }
415  }
416 
417  private:
420  this,
421  "Signals",
422  {"SIGINT", "SIGXCPU"},
423  "List of signal names or numbers to use to schedule a stop. "
424  "If the signal is followed by a '+' the signal is propagated the previously "
425  "registered handler (if any)."};
429  bool m_stopRequested = false;
438  debug() << "Decoding signal declaration '" << sig << "'" << endmsg;
439  if ( sig.empty() || sig == "+" ) {
440  debug() << "Empty signal, ignored" << endmsg;
441  return {-1, false}; // silently ignore empty strings
442  }
443  const SigMap& sigmap( SigMap::instance() );
444  std::string signal = sig;
445  bool propagate = false;
446  // Check if the signal must be propagated
447  if ( signal[signal.size() - 1] == '+' ) {
448  debug() << "Must be propagated to previously registered signal handlers" << endmsg;
449  propagate = true;
450  signal.erase( signal.size() - 1, 1 ); // remove the '+' at the end of the string
451  }
452  int signum = -1;
453  // check if the signal is a number
454  if ( std::isdigit( signal[0] ) ) {
455  std::istringstream ss( signal );
456  ss >> signum;
457  } else {
458  // try to find the signal name in the list of known signals
459  signum = sigmap.signum( signal );
460  }
461  if ( signum < 0 ) {
462  warning() << "Cannot understand signal identifier '" << sig << "', ignored" << endmsg;
463  } else {
464  verbose() << "Matched signal '" << sigmap.name( signum ) << "' (" << signum;
465  const std::string& desc = sigmap.desc( signum );
466  if ( !desc.empty() ) { verbose() << ", " << desc; }
467  verbose() << ")" << endmsg;
468  }
469  return {signum, propagate};
470  }
471  };
472 
473  } // namespace Utils
474 } // namespace Gaudi
475 
476 // Initialization of static data member
478 
479 // ========================================================================
480 // Instantiation of a static factory class used by clients to create instances of this service
483 
484 // Instantiation of a static factory class used by clients to create instances of this service
485 typedef Gaudi::Utils::StopSignalHandler g_u_ssh;
486 DECLARE_COMPONENT( g_u_ssh )
void setSignal(int signum) override
Set the flag for the given signal, as if the signal was received.
StatusCode initialize() override
Definition: Service.cpp:60
sig_atomic_t m_caught[NSIG]
Array of flags for received signals.
Small smart pointer class with automatic reference counting for IInterface.
Definition: IConverter.h:15
T empty(T...args)
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
const std::string & name() const override
Retrieve name of the service.
Definition: Service.cpp:274
StatusCode finalize() override
Definition: Service.cpp:164
SmartIF< IIncidentSvc > m_incidentSvc
Pointer to the incident service.
Implementation of property with value of concrete type.
Definition: Property.h:352
Gaudi::Utils::SignalMonitorSvc g_u_sms
~SignalMonitorSvc() override
Stop monitoring signals and clear the instance pointer.
bool gotSignal(int signum) const override
Check if the given signal has been received.
void ignoreSignal(int signum) override
Remove the specific signal handler for the requested signal, restoring the previous signal handler...
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
constexpr static const auto SUCCESS
Definition: StatusCode.h:85
static void dispatcher(int signum)
Signal handler function.
class MergingTransformer< Out(const vector_of_const_< In > void
void clearSignal(int signum) override
Clear the flag for the given signal, so that a new occurrence can be identified.
T end(T...args)
SmartIF< IFace > as()
Definition: ISvcLocator.h:103
SmartIF< Gaudi::ISignalMonitor > m_signalMonitor
Pointer to the signal monitor service.
bool isFailure() const
Definition: StatusCode.h:130
STL class.
#define DECLARE_COMPONENT(type)
MonitoringMode
Possible monitoring modes.
StatusCode service(const Gaudi::Utils::TypeNameString &name, T *&svc, bool createIf=true)
Templated method to access a service by name.
Definition: ISvcLocator.h:76
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)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
static SignalMonitorSvc * instance()
Method to get the singleton instance.
Implementation of Gaudi::ISignalMonitor.
T isdigit(T...args)
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:50
SignalMonitorSvc(const std::string &name, ISvcLocator *svcLoc)
Initialize internal variables of the service and set the instance pointer.
void handle(const Incident &) override
T erase(T...args)
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.
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:49
static SignalMonitorSvc * s_instance
Pointer to the current instance.
T find(T...args)
T size(T...args)
void monitorSignal(int signum, bool propagate) override
Declare a signal to be monitored.
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
Base class used to extend a class implementing other interfaces.
Definition: extends.h:10
T begin(T...args)
Base class for all Incidents (computing events).
Definition: Incident.h:17
string s
Definition: gaudirun.py:312
constexpr static const auto FAILURE
Definition: StatusCode.h:86
The IEventProcessor is the interface to process events.
#define addSignal(id)
MonitoringMode m_monitored[NSIG]
Array of flags to keep track of monitored signals.
constexpr int SignalOffset
Definition: AppReturnCode.h:34
handler_t m_oldActions[NSIG]
List of replaced signal actions (for the recovery when disable the monitoring).
handler_t m_defaultAction
Helper variable for default signal action.
T for_each(T...args)
Gaudi::Utils::StopSignalHandler g_u_ssh
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition: Service.cpp:277
Helper functions to set/get the application return code.
Definition: __init__.py:1
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:192