The Gaudi Framework  master (e3184c44)
SignalMonitorSvc.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2025 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  typedef struct sigaction handler_t;
39 
42  void monitorSignal( int signum, bool propagate ) override {
43  if ( !m_monitored[signum] ) {
44  handler_t sa;
45  handler_t oldact;
46  sa.sa_handler = SignalMonitorSvc::dispatcher;
47  sigemptyset( &sa.sa_mask );
48  sa.sa_flags = 0;
49  sigaction( signum, &sa, &oldact );
50  m_oldActions[signum] = oldact;
52  }
53  }
54 
57  void ignoreSignal( int signum ) override {
58  if ( m_monitored[signum] ) {
59  sigaction( signum, &m_oldActions[signum], nullptr );
60  m_oldActions[signum] = m_defaultAction;
61  m_monitored[signum] = ignored;
62  }
63  }
64 
66  bool gotSignal( int signum ) const override { return m_caught[signum] != 0; }
67 
69  void setSignal( int signum ) override { m_caught[signum] = 1; }
70 
72  void clearSignal( int signum ) override { m_caught[signum] = 0; }
73 
75  SignalMonitorSvc( const std::string& name, ISvcLocator* svcLoc ) : base_class( name, svcLoc ) {
76  m_defaultAction.sa_handler = SIG_DFL;
77  sigemptyset( &m_defaultAction.sa_mask );
78  m_defaultAction.sa_flags = 0;
79  for ( int i = 0; i < NSIG; ++i ) {
80  m_caught[i] = 0;
81  m_monitored[i] = ignored;
83  }
84 
85  setInstance( this );
86  }
87 
89  ~SignalMonitorSvc() override {
90  for ( int i = 0; i < NSIG; ++i ) ignoreSignal( i );
91  setInstance( nullptr );
92  }
93 
94  private:
97  ignored, //< the signal is not monitored
98  trap, //< the signal is monitored and not propagated to previously registered handlers
99  propagate //< the signal is monitored and propagated to previously registered handlers
100  };
104  sig_atomic_t m_caught[NSIG];
109 
110  void i_handle( int signum ) {
111  m_caught[signum] = 1;
112  if ( m_monitored[signum] == propagate && m_oldActions[signum].sa_handler != SIG_DFL ) {
113  m_oldActions[signum].sa_handler( signum );
114  }
115  }
116 
119 
120  static inline void setInstance( SignalMonitorSvc* i ) { s_instance = i; }
121 
124  static inline SignalMonitorSvc* instance() { return s_instance; }
125 
127  static void dispatcher( int signum );
128  };
129 
130  // Implementation of the signal handler function.
131  void SignalMonitorSvc::dispatcher( int signum ) {
132  if ( instance() ) instance()->i_handle( signum );
133  }
134 
135  } // namespace Utils
136 } // namespace Gaudi
137 
138 #include <cctype>
139 #include <sstream>
140 
141 #include <map>
142 
143 #include <GaudiKernel/HashMap.h>
144 
149 
150 namespace {
151  const char* sig_desc( int signum ) {
152  if ( signum >= NSIG || signum < 0 ) return nullptr;
153  return strsignal( signum );
154  }
155 
157  class SigMap {
158  public:
160  static const SigMap& instance() {
161  static SigMap _instance;
162  return _instance;
163  }
165  inline const std::string& name( int signum ) const { return m_num2id[signum]; }
167  inline const std::string& desc( int signum ) const { return m_num2desc[signum]; }
169  inline int signum( const std::string& str ) const {
170  auto it = m_name2num.find( str );
171  return it != m_name2num.end() ? it->second : -1;
172  }
173 
174  private:
177  SigMap() {
178 #define addSignal( id ) i_addSignal( id, #id );
179 // List of signals from http://en.wikipedia.org/wiki/POSIX_signal
180 #ifdef SIGABRT
181  addSignal( SIGABRT ); // Process aborted
182 #endif
183 #ifdef SIGALRM
184  addSignal( SIGALRM ); // Signal raised by alarm
185 #endif
186 #ifdef SIGBUS
187  addSignal( SIGBUS ); // Bus error: "access to undefined portion of memory object"
188 #endif
189 #ifdef SIGCHLD
190  addSignal( SIGCHLD ); // Child process terminated, stopped (or continued*)
191 #endif
192 #ifdef SIGCONT
193  addSignal( SIGCONT ); // Continue if stopped
194 #endif
195 #ifdef SIGFPE
196  addSignal( SIGFPE ); // Floating point exception: "erroneous arithmetic operation"
197 #endif
198 #ifdef SIGHUP
199  addSignal( SIGHUP ); // Hangup
200 #endif
201 #ifdef SIGILL
202  addSignal( SIGILL ); // Illegal instruction
203 #endif
204 #ifdef SIGINT
205  addSignal( SIGINT ); // Interrupt
206 #endif
207 #ifdef SIGKILL
208  addSignal( SIGKILL ); // Kill (terminate immediately)
209 #endif
210 #ifdef SIGPIPE
211  addSignal( SIGPIPE ); // Write to pipe with no one reading
212 #endif
213 #ifdef SIGQUIT
214  addSignal( SIGQUIT ); // Quit and dump core
215 #endif
216 #ifdef SIGSEGV
217  addSignal( SIGSEGV ); // Segmentation violation
218 #endif
219 #ifdef SIGSTOP
220  addSignal( SIGSTOP ); // Stop executing temporarily
221 #endif
222 #ifdef SIGTERM
223  addSignal( SIGTERM ); // Termination (request to terminate)
224 #endif
225 #ifdef SIGTSTP
226  addSignal( SIGTSTP ); // Terminal stop signal
227 #endif
228 #ifdef SIGTTIN
229  addSignal( SIGTTIN ); // Background process attempting to read from tty ("in")
230 #endif
231 #ifdef SIGTTOU
232  addSignal( SIGTTOU ); // Background process attempting to write to tty ("out")
233 #endif
234 #ifdef SIGUSR1
235  addSignal( SIGUSR1 ); // User-defined 1
236 #endif
237 #ifdef SIGUSR2
238  addSignal( SIGUSR2 ); // User-defined 2
239 #endif
240 #ifdef SIGPOLL
241  addSignal( SIGPOLL ); // Pollable event
242 #endif
243 #ifdef SIGPROF
244  addSignal( SIGPROF ); // Profiling timer expired
245 #endif
246 #ifdef SIGSYS
247  addSignal( SIGSYS ); // Bad syscall
248 #endif
249 #ifdef SIGTRAP
250  addSignal( SIGTRAP ); // Trace/breakpoint trap
251 #endif
252 #ifdef SIGURG
253  addSignal( SIGURG ); // Urgent data available on socket
254 #endif
255 #ifdef SIGVTALRM
256  addSignal( SIGVTALRM ); // Signal raised by timer counting virtual time: "virtual timer expired"
257 #endif
258 #ifdef SIGXCPU
259  addSignal( SIGXCPU ); // CPU time limit exceeded
260 #endif
261 #ifdef SIGXFSZ
262  addSignal( SIGXFSZ ); // File size limit exceeded
263 #endif
264 #undef addSignal
265  }
267  inline void i_addSignal( int signum, const char* signame ) {
268  m_num2id[signum] = signame;
269  m_name2num[signame] = signum;
270  const char* desc = sig_desc( signum );
271  if ( desc ) {
272  m_num2desc[signum] = desc;
273  m_name2num[desc] = signum;
274  }
275  }
276  GaudiUtils::HashMap<std::string, int> m_name2num; //< Map signal string id or description to number
277  GaudiUtils::HashMap<int, std::string> m_num2id; //< Map signal number to string id
278  GaudiUtils::HashMap<int, std::string> m_num2desc; //< Map signal number to description
279  };
280 } // namespace
281 
282 namespace Gaudi {
283  namespace Utils {
293  class StopSignalHandler : public extends<Service, IIncidentListener> {
294  public:
295  using extends::extends;
296  StatusCode initialize() override {
298  if ( sc.isFailure() ) { return sc; }
299  std::string serviceName( "Gaudi::Utils::SignalMonitorSvc" );
300  m_signalMonitor = serviceLocator()->service( serviceName );
301  if ( !m_signalMonitor ) {
302  error() << "Cannot retrieve " << serviceName << endmsg;
303  return StatusCode::FAILURE;
304  }
305  serviceName = "IncidentSvc";
306  m_incidentSvc = serviceLocator()->service( serviceName );
307  if ( !m_incidentSvc ) {
308  error() << "Cannot retrieve " << serviceName << endmsg;
309  return StatusCode::FAILURE;
310  }
311  // Get the IMainAppStatus interface of the ApplicationMgr
313  if ( !m_appProperty ) {
314  warning() << "Cannot retrieve IProperty interface of ApplicationMgr, "
315  "the return code will not be changed"
316  << endmsg;
317  }
318  // Decode the signal names
319  for ( const auto& signame : m_usedSignals ) {
320  auto sigid = i_decodeSignal( signame );
321  if ( sigid.first >= 0 ) { m_signals[sigid.first] = sigid.second; }
322  }
323  debug() << "Stopping on the signals:" << endmsg;
324  const SigMap& sigmap( SigMap::instance() );
325  for ( const auto& s : m_signals ) {
326  debug() << "\t" << sigmap.name( s.first ) << ": " << sigmap.desc( s.first ) << " (" << s.first << ")";
327  if ( s.second ) debug() << " propagated";
328  debug() << endmsg;
329  // tell the signal monitor that we are interested in these signals
330  m_signalMonitor->monitorSignal( s.first, s.second );
331  }
332  m_stopRequested = false;
333  debug() << "Register to the IncidentSvc" << endmsg;
334  m_incidentSvc->addListener( this, IncidentType::BeginEvent );
335  return StatusCode::SUCCESS;
336  }
337  StatusCode finalize() override {
338  m_incidentSvc->removeListener( this, IncidentType::BeginEvent );
340  // disable the monitoring of the signals
341  std::for_each( std::begin( m_signals ), std::end( m_signals ), [&]( const std::pair<int, bool>& s ) {
342  // tell the signal monitor that we are interested in these signals
343  m_signalMonitor->ignoreSignal( s.first );
344  } );
346  return Service::finalize();
347  }
348 
349  void handle( const Incident& ) override {
350  if ( !m_stopRequested ) {
351  const SigMap& sigmap( SigMap::instance() );
352  for ( const auto& s : m_signals ) {
353  if ( !m_signalMonitor->gotSignal( s.first ) ) continue;
354  warning() << "Received signal '" << sigmap.name( s.first ) << "' (" << s.first;
355  const std::string& desc = sigmap.desc( s.first );
356  if ( !desc.empty() ) warning() << ", " << desc;
357  warning() << ")" << endmsg;
358  m_stopRequested = true;
359  // Report the termination by signal at the end of the application
362  error() << "Could not set return code of the application (" << SignalOffset + s.first << ")" << endmsg;
363  }
364  }
365  if ( m_stopRequested ) {
366  auto ep = serviceLocator()->as<IEventProcessor>();
367  if ( ep ) {
368  warning() << "Scheduling a stop" << endmsg;
369  ep->stopRun().ignore();
370  } else {
371  warning() << "Cannot stop the processing because the IEventProcessor interface cannot be retrieved."
372  << endmsg;
373  }
374  }
375  }
376  }
377 
378  private:
381  this,
382  "Signals",
383  { "SIGINT", "SIGXCPU" },
384  "List of signal names or numbers to use to schedule a stop. "
385  "If the signal is followed by a '+' the signal is propagated the previously "
386  "registered handler (if any)." };
388  std::map<int, bool> m_signals;
390  bool m_stopRequested = false;
398  std::pair<int, bool> i_decodeSignal( const std::string& sig ) {
399  debug() << "Decoding signal declaration '" << sig << "'" << endmsg;
400  if ( sig.empty() || sig == "+" ) {
401  debug() << "Empty signal, ignored" << endmsg;
402  return { -1, false }; // silently ignore empty strings
403  }
404  const SigMap& sigmap( SigMap::instance() );
405  std::string signal = sig;
406  bool propagate = false;
407  // Check if the signal must be propagated
408  if ( signal[signal.size() - 1] == '+' ) {
409  debug() << "Must be propagated to previously registered signal handlers" << endmsg;
410  propagate = true;
411  signal.erase( signal.size() - 1, 1 ); // remove the '+' at the end of the string
412  }
413  int signum = -1;
414  // check if the signal is a number
415  if ( std::isdigit( signal[0] ) ) {
416  std::istringstream ss( signal );
417  ss >> signum;
418  } else {
419  // try to find the signal name in the list of known signals
420  signum = sigmap.signum( signal );
421  }
422  if ( signum < 0 ) {
423  warning() << "Cannot understand signal identifier '" << sig << "', ignored" << endmsg;
424  } else {
425  verbose() << "Matched signal '" << sigmap.name( signum ) << "' (" << signum;
426  const std::string& desc = sigmap.desc( signum );
427  if ( !desc.empty() ) { verbose() << ", " << desc; }
428  verbose() << ")" << endmsg;
429  }
430  return { signum, propagate };
431  }
432  };
433 
434  } // namespace Utils
435 } // namespace Gaudi
436 
437 // Initialization of static data member
439 
440 // ========================================================================
441 // Instantiation of a static factory class used by clients to create instances of this service
444 
445 // Instantiation of a static factory class used by clients to create instances of this service
446 typedef Gaudi::Utils::StopSignalHandler g_u_ssh;
Gaudi::Utils::SignalMonitorSvc::ignored
@ ignored
Definition: SignalMonitorSvc.cpp:97
Gaudi::Utils::SignalMonitorSvc::m_caught
sig_atomic_t m_caught[NSIG]
Array of flags for received signals.
Definition: SignalMonitorSvc.cpp:104
Gaudi::ReturnCode::SignalOffset
constexpr int SignalOffset
Definition: AppReturnCode.h:43
IEventProcessor
Definition: IEventProcessor.h:22
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:108
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:42
AppReturnCode.h
Gaudi::Utils::SignalMonitorSvc::trap
@ trap
Definition: SignalMonitorSvc.cpp:98
addSignal
#define addSignal(id)
Gaudi::Utils::StopSignalHandler::initialize
StatusCode initialize() override
Definition: SignalMonitorSvc.cpp:296
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:388
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:88
ISvcLocator
Definition: ISvcLocator.h:42
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:380
g_u_sms
Gaudi::Utils::SignalMonitorSvc g_u_sms
Definition: SignalMonitorSvc.cpp:442
Gaudi::Utils::SignalMonitorSvc::s_instance
static SignalMonitorSvc * s_instance
Pointer to the current instance.
Definition: SignalMonitorSvc.cpp:118
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:398
Gaudi::Utils::SignalMonitorSvc::dispatcher
static void dispatcher(int signum)
Signal handler function.
Definition: SignalMonitorSvc.cpp:131
cpluginsvc._instance
_instance
Definition: cpluginsvc.py:80
Service::finalize
StatusCode finalize() override
Definition: Service.cpp:223
HashMap.h
IIncidentSvc.h
Gaudi::Utils::SignalMonitorSvc::i_handle
void i_handle(int signum)
Definition: SignalMonitorSvc.cpp:110
Gaudi::Utils::StopSignalHandler::m_incidentSvc
SmartIF< IIncidentSvc > m_incidentSvc
Pointer to the incident service.
Definition: SignalMonitorSvc.cpp:394
Gaudi::Utils::SignalMonitorSvc::~SignalMonitorSvc
~SignalMonitorSvc() override
Stop monitoring signals and clear the instance pointer.
Definition: SignalMonitorSvc.cpp:89
Gaudi::Utils::begin
AttribStringParser::Iterator begin(const AttribStringParser &parser)
Definition: AttribStringParser.h:135
Service::name
const std::string & name() const override
Retrieve name of the service
Definition: Service.cpp:333
StatusCode
Definition: StatusCode.h:64
Gaudi::cxx::for_each
void for_each(ContainerOfSynced &c, Fun &&f)
Definition: SynchronizedValue.h:98
Gaudi::setAppReturnCode
StatusCode setAppReturnCode(SmartIF< IProperty > &appmgr, int value, bool force=false)
Set the application return code.
Definition: AppReturnCode.h:58
Gaudi::Utils::SignalMonitorSvc::MonitoringMode
MonitoringMode
Possible monitoring modes.
Definition: SignalMonitorSvc.cpp:96
ISignalMonitor.h
CommonMessaging
Definition: CommonMessaging.h:65
Gaudi::Utils::SignalMonitorSvc::m_monitored
MonitoringMode m_monitored[NSIG]
Array of flags to keep track of monitored signals.
Definition: SignalMonitorSvc.cpp:102
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:57
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:198
Gaudi::Utils::StopSignalHandler
Service that stop the processing if a signal is received.
Definition: SignalMonitorSvc.cpp:293
extends
Base class used to extend a class implementing other interfaces.
Definition: extends.h:19
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:337
Service.h
SmartIF::as
SmartIF< IFace > as() const
return a new SmartIF instance to another interface
Definition: SmartIF.h:110
StatusCode::isFailure
bool isFailure() const
Definition: StatusCode.h:129
Gaudi::Utils::SignalMonitorSvc::setInstance
static void setInstance(SignalMonitorSvc *i)
Definition: SignalMonitorSvc.cpp:120
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:99
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:75
IIncidentListener.h
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:45
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:69
Gaudi::Utils::StopSignalHandler::m_stopRequested
bool m_stopRequested
Flag to remember if the stop has been requested because of a signal.
Definition: SignalMonitorSvc.cpp:390
Gaudi::Utils::SignalMonitorSvc::propagate
@ propagate
Definition: SignalMonitorSvc.cpp:99
Gaudi::Utils::StopSignalHandler::handle
void handle(const Incident &) override
Definition: SignalMonitorSvc.cpp:349
Gaudi::Utils::StopSignalHandler::m_appProperty
SmartIF< IProperty > m_appProperty
Pointer to the interface to set the return code of the application.
Definition: SignalMonitorSvc.cpp:396
Gaudi::Utils::SignalMonitorSvc::instance
static SignalMonitorSvc * instance()
Method to get the singleton instance.
Definition: SignalMonitorSvc.cpp:124
GaudiUtils::HashMap
Definition: HashMap.h:80
IOTest.end
end
Definition: IOTest.py:125
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:100
Gaudi::Utils::SignalMonitorSvc::m_defaultAction
handler_t m_defaultAction
Helper variable for default signal action.
Definition: SignalMonitorSvc.cpp:106
Gaudi::Utils::SignalMonitorSvc::handler_t
struct sigaction handler_t
Definition: SignalMonitorSvc.cpp:38
Incident
Definition: Incident.h:24
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:72
IEventProcessor.h
Gaudi::Utils::StopSignalHandler::m_signalMonitor
SmartIF< Gaudi::ISignalMonitor > m_signalMonitor
Pointer to the signal monitor service.
Definition: SignalMonitorSvc.cpp:392
Gaudi::Property
Implementation of property with value of concrete type.
Definition: Property.h:35
Service::serviceLocator
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator
Definition: Service.cpp:336
Gaudi::Utils::SignalMonitorSvc::gotSignal
bool gotSignal(int signum) const override
Check if the given signal has been received.
Definition: SignalMonitorSvc.cpp:66