Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  master (f31105fd)
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 * (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 /*
12  * SignalMonitorSvc.cpp
13  *
14  * Created on: Apr 14, 2010
15  * Author: Marco Clemencic
16  */
17 #include <GaudiKernel/Service.h>
19 
20 #include <csignal>
21 #include <cstring>
22 #include <iostream>
23 
24 namespace Gaudi {
25  namespace Utils {
36  class SignalMonitorSvc : public extends<Service, Gaudi::ISignalMonitor> {
37  public:
38 #ifdef _WIN32
39  typedef void( __cdecl* handler_t )( int );
40 #else
41  typedef struct sigaction handler_t;
42 #endif
43 
46  void monitorSignal( int signum, bool propagate ) override {
47  if ( !m_monitored[signum] ) {
48  handler_t sa;
49  handler_t oldact;
50 #ifdef _WIN32
52  oldact = signal( signum, sa );
53 #else
54  sa.sa_handler = SignalMonitorSvc::dispatcher;
55  sigemptyset( &sa.sa_mask );
56  sa.sa_flags = 0;
57  sigaction( signum, &sa, &oldact );
58 #endif
59  m_oldActions[signum] = oldact;
61  }
62  }
63 
66  void ignoreSignal( int signum ) override {
67  if ( m_monitored[signum] ) {
68 #ifdef _WIN32
69  (void)signal( signum, m_oldActions[signum] );
70 #else
71  sigaction( signum, &m_oldActions[signum], nullptr );
72 #endif
73  m_oldActions[signum] = m_defaultAction;
74  m_monitored[signum] = ignored;
75  }
76  }
77 
79  bool gotSignal( int signum ) const override { return m_caught[signum] != 0; }
80 
82  void setSignal( int signum ) override { m_caught[signum] = 1; }
83 
85  void clearSignal( int signum ) override { m_caught[signum] = 0; }
86 
88  SignalMonitorSvc( const std::string& name, ISvcLocator* svcLoc ) : base_class( name, svcLoc ) {
89 #ifdef _WIN32
90  m_defaultAction = SIG_DFL;
91 #else
92  m_defaultAction.sa_handler = SIG_DFL;
93  sigemptyset( &m_defaultAction.sa_mask );
94  m_defaultAction.sa_flags = 0;
95 #endif
96  for ( int i = 0; i < NSIG; ++i ) {
97  m_caught[i] = 0;
98  m_monitored[i] = ignored;
100  }
101 
102  setInstance( this );
103  }
104 
106  ~SignalMonitorSvc() override {
107  for ( int i = 0; i < NSIG; ++i ) ignoreSignal( i );
108  setInstance( nullptr );
109  }
110 
111  private:
114  ignored, //< the signal is not monitored
115  trap, //< the signal is monitored and not propagated to previously registered handlers
116  propagate //< the signal is monitored and propagated to previously registered handlers
117  };
121  sig_atomic_t m_caught[NSIG];
123 #ifdef _WIN32
124  handler_t m_defaultAction{ nullptr };
125 #else
127 #endif
128  handler_t m_oldActions[NSIG];
130 
131  void i_handle( int signum ) {
132  m_caught[signum] = 1;
133  if ( m_monitored[signum] == propagate &&
134 #ifdef _WIN32
135  m_oldActions[signum] != SIG_DFL
136 #else
137  m_oldActions[signum].sa_handler != SIG_DFL
138 #endif
139  ) {
140 #ifdef _WIN32
141  m_oldActions[signum]( signum );
142 #else
143  m_oldActions[signum].sa_handler( signum );
144 #endif
145  }
146  }
147 
150 
151  static inline void setInstance( SignalMonitorSvc* i ) { s_instance = i; }
152 
155  static inline SignalMonitorSvc* instance() { return s_instance; }
156 
158  static void dispatcher( int signum );
159  };
160 
161  // Implementation of the signal handler function.
162  void SignalMonitorSvc::dispatcher( int signum ) {
163  if ( instance() ) instance()->i_handle( signum );
164  }
165 
166  } // namespace Utils
167 } // namespace Gaudi
168 
169 #include <cctype>
170 #include <sstream>
171 
172 #include <map>
173 
174 #include <GaudiKernel/HashMap.h>
175 
180 
181 namespace {
182  // hack because windows doesn't provide sys_siglist
183  const char* sig_desc( int signum ) {
184  if ( signum >= NSIG || signum < 0 ) return nullptr;
185 #ifdef _WIN32
186  switch ( signum ) {
187  case SIGINT:
188  return "Interrupt";
189  case SIGILL:
190  return "Illegal instruction";
191  case SIGFPE:
192  return "Floating point exception";
193  case SIGSEGV:
194  return "Segmentation fault";
195  case SIGTERM:
196  return "Terminated";
197  case SIGBREAK:
198  return "Trace/breakpoint trap";
199  case SIGABRT:
200  return "Aborted";
201  default:
202  return 0;
203  }
204 #else
205  return strsignal( signum );
206 #endif
207  }
208 
210  class SigMap {
211  public:
213  static const SigMap& instance() {
214  static SigMap _instance;
215  return _instance;
216  }
218  inline const std::string& name( int signum ) const { return m_num2id[signum]; }
220  inline const std::string& desc( int signum ) const { return m_num2desc[signum]; }
222  inline int signum( const std::string& str ) const {
223  auto it = m_name2num.find( str );
224  return it != m_name2num.end() ? it->second : -1;
225  }
226 
227  private:
230  SigMap() {
231 #define addSignal( id ) i_addSignal( id, #id );
232 // List of signals from http://en.wikipedia.org/wiki/POSIX_signal
233 #ifdef SIGABRT
234  addSignal( SIGABRT ); // Process aborted
235 #endif
236 #ifdef SIGALRM
237  addSignal( SIGALRM ); // Signal raised by alarm
238 #endif
239 #ifdef SIGBUS
240  addSignal( SIGBUS ); // Bus error: "access to undefined portion of memory object"
241 #endif
242 #ifdef SIGCHLD
243  addSignal( SIGCHLD ); // Child process terminated, stopped (or continued*)
244 #endif
245 #ifdef SIGCONT
246  addSignal( SIGCONT ); // Continue if stopped
247 #endif
248 #ifdef SIGFPE
249  addSignal( SIGFPE ); // Floating point exception: "erroneous arithmetic operation"
250 #endif
251 #ifdef SIGHUP
252  addSignal( SIGHUP ); // Hangup
253 #endif
254 #ifdef SIGILL
255  addSignal( SIGILL ); // Illegal instruction
256 #endif
257 #ifdef SIGINT
258  addSignal( SIGINT ); // Interrupt
259 #endif
260 #ifdef SIGKILL
261  addSignal( SIGKILL ); // Kill (terminate immediately)
262 #endif
263 #ifdef SIGPIPE
264  addSignal( SIGPIPE ); // Write to pipe with no one reading
265 #endif
266 #ifdef SIGQUIT
267  addSignal( SIGQUIT ); // Quit and dump core
268 #endif
269 #ifdef SIGSEGV
270  addSignal( SIGSEGV ); // Segmentation violation
271 #endif
272 #ifdef SIGSTOP
273  addSignal( SIGSTOP ); // Stop executing temporarily
274 #endif
275 #ifdef SIGTERM
276  addSignal( SIGTERM ); // Termination (request to terminate)
277 #endif
278 #ifdef SIGTSTP
279  addSignal( SIGTSTP ); // Terminal stop signal
280 #endif
281 #ifdef SIGTTIN
282  addSignal( SIGTTIN ); // Background process attempting to read from tty ("in")
283 #endif
284 #ifdef SIGTTOU
285  addSignal( SIGTTOU ); // Background process attempting to write to tty ("out")
286 #endif
287 #ifdef SIGUSR1
288  addSignal( SIGUSR1 ); // User-defined 1
289 #endif
290 #ifdef SIGUSR2
291  addSignal( SIGUSR2 ); // User-defined 2
292 #endif
293 #ifdef SIGPOLL
294  addSignal( SIGPOLL ); // Pollable event
295 #endif
296 #ifdef SIGPROF
297  addSignal( SIGPROF ); // Profiling timer expired
298 #endif
299 #ifdef SIGSYS
300  addSignal( SIGSYS ); // Bad syscall
301 #endif
302 #ifdef SIGTRAP
303  addSignal( SIGTRAP ); // Trace/breakpoint trap
304 #endif
305 #ifdef SIGURG
306  addSignal( SIGURG ); // Urgent data available on socket
307 #endif
308 #ifdef SIGVTALRM
309  addSignal( SIGVTALRM ); // Signal raised by timer counting virtual time: "virtual timer expired"
310 #endif
311 #ifdef SIGXCPU
312  addSignal( SIGXCPU ); // CPU time limit exceeded
313 #endif
314 #ifdef SIGXFSZ
315  addSignal( SIGXFSZ ); // File size limit exceeded
316 #endif
317 #undef addSignal
318  }
320  inline void i_addSignal( int signum, const char* signame ) {
321  m_num2id[signum] = signame;
322  m_name2num[signame] = signum;
323  const char* desc = sig_desc( signum );
324  if ( desc ) {
325  m_num2desc[signum] = desc;
326  m_name2num[desc] = signum;
327  }
328  }
329  GaudiUtils::HashMap<std::string, int> m_name2num; //< Map signal string id or description to number
330  GaudiUtils::HashMap<int, std::string> m_num2id; //< Map signal number to string id
331  GaudiUtils::HashMap<int, std::string> m_num2desc; //< Map signal number to description
332  };
333 } // namespace
334 
335 namespace Gaudi {
336  namespace Utils {
346  class StopSignalHandler : public extends<Service, IIncidentListener> {
347  public:
348  using extends::extends;
349  StatusCode initialize() override {
351  if ( sc.isFailure() ) { return sc; }
352  std::string serviceName( "Gaudi::Utils::SignalMonitorSvc" );
353  m_signalMonitor = serviceLocator()->service( serviceName );
354  if ( !m_signalMonitor ) {
355  error() << "Cannot retrieve " << serviceName << endmsg;
356  return StatusCode::FAILURE;
357  }
358  serviceName = "IncidentSvc";
359  m_incidentSvc = serviceLocator()->service( serviceName );
360  if ( !m_incidentSvc ) {
361  error() << "Cannot retrieve " << serviceName << endmsg;
362  return StatusCode::FAILURE;
363  }
364  // Get the IMainAppStatus interface of the ApplicationMgr
366  if ( !m_appProperty ) {
367  warning() << "Cannot retrieve IProperty interface of ApplicationMgr, "
368  "the return code will not be changed"
369  << endmsg;
370  }
371  // Decode the signal names
372  for ( const auto& signame : m_usedSignals ) {
373  auto sigid = i_decodeSignal( signame );
374  if ( sigid.first >= 0 ) { m_signals[sigid.first] = sigid.second; }
375  }
376  debug() << "Stopping on the signals:" << endmsg;
377  const SigMap& sigmap( SigMap::instance() );
378  for ( const auto& s : m_signals ) {
379  debug() << "\t" << sigmap.name( s.first ) << ": " << sigmap.desc( s.first ) << " (" << s.first << ")";
380  if ( s.second ) debug() << " propagated";
381  debug() << endmsg;
382  // tell the signal monitor that we are interested in these signals
383  m_signalMonitor->monitorSignal( s.first, s.second );
384  }
385  m_stopRequested = false;
386  debug() << "Register to the IncidentSvc" << endmsg;
387  m_incidentSvc->addListener( this, IncidentType::BeginEvent );
388  return StatusCode::SUCCESS;
389  }
390  StatusCode finalize() override {
391  m_incidentSvc->removeListener( this, IncidentType::BeginEvent );
393  // disable the monitoring of the signals
395  // tell the signal monitor that we are interested in these signals
396  m_signalMonitor->ignoreSignal( s.first );
397  } );
399  return Service::finalize();
400  }
401 
402  void handle( const Incident& ) override {
403  if ( !m_stopRequested ) {
404  const SigMap& sigmap( SigMap::instance() );
405  for ( const auto& s : m_signals ) {
406  if ( !m_signalMonitor->gotSignal( s.first ) ) continue;
407  warning() << "Received signal '" << sigmap.name( s.first ) << "' (" << s.first;
408  const std::string& desc = sigmap.desc( s.first );
409  if ( !desc.empty() ) warning() << ", " << desc;
410  warning() << ")" << endmsg;
411  m_stopRequested = true;
412  // Report the termination by signal at the end of the application
415  error() << "Could not set return code of the application (" << SignalOffset + s.first << ")" << endmsg;
416  }
417  }
418  if ( m_stopRequested ) {
419  auto ep = serviceLocator()->as<IEventProcessor>();
420  if ( ep ) {
421  warning() << "Scheduling a stop" << endmsg;
422  ep->stopRun().ignore();
423  } else {
424  warning() << "Cannot stop the processing because the IEventProcessor interface cannot be retrieved."
425  << endmsg;
426  }
427  }
428  }
429  }
430 
431  private:
434  this,
435  "Signals",
436  { "SIGINT", "SIGXCPU" },
437  "List of signal names or numbers to use to schedule a stop. "
438  "If the signal is followed by a '+' the signal is propagated the previously "
439  "registered handler (if any)." };
443  bool m_stopRequested = false;
452  debug() << "Decoding signal declaration '" << sig << "'" << endmsg;
453  if ( sig.empty() || sig == "+" ) {
454  debug() << "Empty signal, ignored" << endmsg;
455  return { -1, false }; // silently ignore empty strings
456  }
457  const SigMap& sigmap( SigMap::instance() );
458  std::string signal = sig;
459  bool propagate = false;
460  // Check if the signal must be propagated
461  if ( signal[signal.size() - 1] == '+' ) {
462  debug() << "Must be propagated to previously registered signal handlers" << endmsg;
463  propagate = true;
464  signal.erase( signal.size() - 1, 1 ); // remove the '+' at the end of the string
465  }
466  int signum = -1;
467  // check if the signal is a number
468  if ( std::isdigit( signal[0] ) ) {
469  std::istringstream ss( signal );
470  ss >> signum;
471  } else {
472  // try to find the signal name in the list of known signals
473  signum = sigmap.signum( signal );
474  }
475  if ( signum < 0 ) {
476  warning() << "Cannot understand signal identifier '" << sig << "', ignored" << endmsg;
477  } else {
478  verbose() << "Matched signal '" << sigmap.name( signum ) << "' (" << signum;
479  const std::string& desc = sigmap.desc( signum );
480  if ( !desc.empty() ) { verbose() << ", " << desc; }
481  verbose() << ")" << endmsg;
482  }
483  return { signum, propagate };
484  }
485  };
486 
487  } // namespace Utils
488 } // namespace Gaudi
489 
490 // Initialization of static data member
492 
493 // ========================================================================
494 // Instantiation of a static factory class used by clients to create instances of this service
497 
498 // Instantiation of a static factory class used by clients to create instances of this service
499 typedef Gaudi::Utils::StopSignalHandler g_u_ssh;
Gaudi::Utils::SignalMonitorSvc::ignored
@ ignored
Definition: SignalMonitorSvc.cpp:114
Gaudi::Utils::SignalMonitorSvc::m_caught
sig_atomic_t m_caught[NSIG]
Array of flags for received signals.
Definition: SignalMonitorSvc.cpp:121
std::isdigit
T isdigit(T... args)
Gaudi::ReturnCode::SignalOffset
constexpr int SignalOffset
Definition: AppReturnCode.h:44
IEventProcessor
Definition: IEventProcessor.h:24
std::for_each
T for_each(T... args)
Gaudi::Utils::SignalMonitorSvc::m_oldActions
handler_t m_oldActions[NSIG]
List of replaced signal actions (for the recovery when disable the monitoring).
Definition: SignalMonitorSvc.cpp:129
Service::initialize
StatusCode initialize() override
Definition: Service.cpp:118
Gaudi::Utils::SignalMonitorSvc::monitorSignal
void monitorSignal(int signum, bool propagate) override
Declare a signal to be monitored.
Definition: SignalMonitorSvc.cpp:46
std::string
STL class.
AppReturnCode.h
Gaudi::Utils::SignalMonitorSvc::trap
@ trap
Definition: SignalMonitorSvc.cpp:115
std::pair
addSignal
#define addSignal(id)
Gaudi::Utils::StopSignalHandler::initialize
StatusCode initialize() override
Definition: SignalMonitorSvc.cpp:349
Gaudi::Utils::StopSignalHandler::m_signals
std::map< int, bool > m_signals
Map of monitored signal numbers to the flag telling if they have to be propagated or not.
Definition: SignalMonitorSvc.cpp:441
gaudirun.s
string s
Definition: gaudirun.py:346
SmartIF::reset
void reset(TYPE *ptr=nullptr)
Set the internal pointer to the passed one disposing of the old one.
Definition: SmartIF.h:96
std::string::find
T find(T... args)
ISvcLocator
Definition: ISvcLocator.h:46
Gaudi::Utils::StopSignalHandler::m_usedSignals
Gaudi::Property< std::vector< std::string > > m_usedSignals
List of signal names or numbers (encoded as strings) to use to schedule a stop.
Definition: SignalMonitorSvc.cpp:433
g_u_sms
Gaudi::Utils::SignalMonitorSvc g_u_sms
Definition: SignalMonitorSvc.cpp:495
std::istringstream
STL class.
Gaudi::Utils::SignalMonitorSvc::s_instance
static SignalMonitorSvc * s_instance
Pointer to the current instance.
Definition: SignalMonitorSvc.cpp:149
Gaudi::Utils::StopSignalHandler::i_decodeSignal
std::pair< int, bool > i_decodeSignal(const std::string &sig)
Function to translate the signal name to the signal number.
Definition: SignalMonitorSvc.cpp:451
Gaudi::Utils::SignalMonitorSvc::dispatcher
static void dispatcher(int signum)
Signal handler function.
Definition: SignalMonitorSvc.cpp:162
cpluginsvc._instance
_instance
Definition: cpluginsvc.py:80
Service::finalize
StatusCode finalize() override
Definition: Service.cpp:222
HashMap.h
IIncidentSvc.h
Gaudi::Utils::SignalMonitorSvc::i_handle
void i_handle(int signum)
Definition: SignalMonitorSvc.cpp:131
Gaudi::Utils::StopSignalHandler::m_incidentSvc
SmartIF< IIncidentSvc > m_incidentSvc
Pointer to the incident service.
Definition: SignalMonitorSvc.cpp:447
Gaudi::Utils::SignalMonitorSvc::~SignalMonitorSvc
~SignalMonitorSvc() override
Stop monitoring signals and clear the instance pointer.
Definition: SignalMonitorSvc.cpp:106
Service::name
const std::string & name() const override
Retrieve name of the service
Definition: Service.cpp:332
StatusCode
Definition: StatusCode.h:65
Gaudi::setAppReturnCode
StatusCode setAppReturnCode(SmartIF< IProperty > &appmgr, int value, bool force=false)
Set the application return code.
Definition: AppReturnCode.h:59
Gaudi::Utils::SignalMonitorSvc::MonitoringMode
MonitoringMode
Possible monitoring modes.
Definition: SignalMonitorSvc.cpp:113
ISignalMonitor.h
CommonMessaging
Definition: CommonMessaging.h:66
Gaudi::Utils::SignalMonitorSvc::m_monitored
MonitoringMode m_monitored[NSIG]
Array of flags to keep track of monitored signals.
Definition: SignalMonitorSvc.cpp:119
Gaudi::Utils::SignalMonitorSvc::ignoreSignal
void ignoreSignal(int signum) override
Remove the specific signal handler for the requested signal, restoring the previous signal handler.
Definition: SignalMonitorSvc.cpp:66
SmartIF< Gaudi::ISignalMonitor >
genconfuser.verbose
verbose
Definition: genconfuser.py:28
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:202
Gaudi::Utils::StopSignalHandler
Service that stop the processing if a signal is received.
Definition: SignalMonitorSvc.cpp:346
std::map< int, bool >
extends
Base class used to extend a class implementing other interfaces.
Definition: extends.h:20
Gaudi
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition: __init__.py:1
Gaudi::Utils::SignalMonitorSvc
Implementation of Gaudi::ISignalMonitor.
Definition: SignalMonitorSvc.cpp:36
Gaudi::Utils::StopSignalHandler::finalize
StatusCode finalize() override
Definition: SignalMonitorSvc.cpp:390
Service.h
SmartIF::as
SmartIF< IFace > as() const
return a new SmartIF instance to another interface
Definition: SmartIF.h:117
StatusCode::isFailure
bool isFailure() const
Definition: StatusCode.h:130
Gaudi::Utils::SignalMonitorSvc::setInstance
static void setInstance(SignalMonitorSvc *i)
Definition: SignalMonitorSvc.cpp:151
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:100
ConditionsStallTest.name
name
Definition: ConditionsStallTest.py:77
Gaudi::Utils::SignalMonitorSvc::SignalMonitorSvc
SignalMonitorSvc(const std::string &name, ISvcLocator *svcLoc)
Initialize internal variables of the service and set the instance pointer.
Definition: SignalMonitorSvc.cpp:88
std::begin
T begin(T... args)
IIncidentListener.h
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:46
Gaudi::Utils::SignalMonitorSvc::setSignal
void setSignal(int signum) override
Set the flag for the given signal, as if the signal was received.
Definition: SignalMonitorSvc.cpp:82
Gaudi::Utils::StopSignalHandler::m_stopRequested
bool m_stopRequested
Flag to remember if the stop has been requested because of a signal.
Definition: SignalMonitorSvc.cpp:443
Gaudi::Utils::SignalMonitorSvc::propagate
@ propagate
Definition: SignalMonitorSvc.cpp:116
Gaudi::Utils::StopSignalHandler::handle
void handle(const Incident &) override
Definition: SignalMonitorSvc.cpp:402
std::string::empty
T empty(T... args)
Gaudi::Utils::StopSignalHandler::m_appProperty
SmartIF< IProperty > m_appProperty
Pointer to the interface to set the return code of the application.
Definition: SignalMonitorSvc.cpp:449
Gaudi::Utils::SignalMonitorSvc::instance
static SignalMonitorSvc * instance()
Method to get the singleton instance.
Definition: SignalMonitorSvc.cpp:155
std::end
T end(T... args)
GaudiUtils::HashMap
Definition: HashMap.h:83
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:101
Gaudi::Utils::SignalMonitorSvc::m_defaultAction
handler_t m_defaultAction
Helper variable for default signal action.
Definition: SignalMonitorSvc.cpp:126
Gaudi::Utils::SignalMonitorSvc::handler_t
struct sigaction handler_t
Definition: SignalMonitorSvc.cpp:41
Incident
Definition: Incident.h:27
Gaudi::Utils::SignalMonitorSvc::clearSignal
void clearSignal(int signum) override
Clear the flag for the given signal, so that a new occurrence can be identified.
Definition: SignalMonitorSvc.cpp:85
IEventProcessor.h
Gaudi::Utils::StopSignalHandler::m_signalMonitor
SmartIF< Gaudi::ISignalMonitor > m_signalMonitor
Pointer to the signal monitor service.
Definition: SignalMonitorSvc.cpp:445
Gaudi::Property
Implementation of property with value of concrete type.
Definition: Property.h:37
Service::serviceLocator
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator
Definition: Service.cpp:335
Gaudi::Utils::SignalMonitorSvc::gotSignal
bool gotSignal(int signum) const override
Check if the given signal has been received.
Definition: SignalMonitorSvc.cpp:79