The Gaudi Framework  master (b9786168)
Loading...
Searching...
No Matches
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
24namespace 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 );
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;
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 };
101
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
150namespace {
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
282namespace Gaudi {
283 namespace Utils {
293 class StopSignalHandler : public extends<Service, IIncidentListener> {
294 public:
295 using extends::extends;
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 );
339 m_incidentSvc.reset();
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 } );
345 m_signalMonitor.reset();
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
361 if ( Gaudi::setAppReturnCode( m_appProperty, SignalOffset + s.first ).isFailure() ) {
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)." };
387
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
446typedef Gaudi::Utils::StopSignalHandler g_u_ssh;
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define DECLARE_COMPONENT(type)
Gaudi::Utils::SignalMonitorSvc g_u_sms
#define addSignal(id)
Gaudi::Utils::StopSignalHandler g_u_ssh
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
Implementation of Gaudi::ISignalMonitor.
void ignoreSignal(int signum) override
Remove the specific signal handler for the requested signal, restoring the previous signal handler.
void clearSignal(int signum) override
Clear the flag for the given signal, so that a new occurrence can be identified.
handler_t m_defaultAction
Helper variable for default signal action.
SignalMonitorSvc(const std::string &name, ISvcLocator *svcLoc)
Initialize internal variables of the service and set the instance pointer.
static void dispatcher(int signum)
Signal handler function.
sig_atomic_t m_caught[NSIG]
Array of flags for received signals.
bool gotSignal(int signum) const override
Check if the given signal has been received.
~SignalMonitorSvc() override
Stop monitoring signals and clear the instance pointer.
static void setInstance(SignalMonitorSvc *i)
void setSignal(int signum) override
Set the flag for the given signal, as if the signal was received.
MonitoringMode
Possible monitoring modes.
static SignalMonitorSvc * instance()
Method to get the singleton instance.
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).
void monitorSignal(int signum, bool propagate) override
Declare a signal to be monitored.
static SignalMonitorSvc * s_instance
Pointer to the current instance.
Service that stop the processing if a signal is received.
bool m_stopRequested
Flag to remember if the stop has been requested because of a signal.
Gaudi::Property< std::vector< std::string > > m_usedSignals
List of signal names or numbers (encoded as strings) to use to schedule a stop.
std::pair< int, bool > i_decodeSignal(const std::string &sig)
Function to translate the signal name to the signal number.
SmartIF< IIncidentSvc > m_incidentSvc
Pointer to the incident service.
SmartIF< Gaudi::ISignalMonitor > m_signalMonitor
Pointer to the signal monitor service.
std::map< int, bool > m_signals
Map of monitored signal numbers to the flag telling if they have to be propagated or not.
void handle(const Incident &) override
SmartIF< IProperty > m_appProperty
Pointer to the interface to set the return code of the application.
The IEventProcessor is the interface to process events.
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition ISvcLocator.h:42
virtual SmartIF< IService > & service(const Gaudi::Utils::TypeNameString &typeName, const bool createIf=true)=0
Returns a smart pointer to a service.
SmartIF< IFace > as()
Definition ISvcLocator.h:64
Base class for all Incidents (computing events).
Definition Incident.h:24
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition Service.cpp:336
StatusCode finalize() override
Definition Service.cpp:223
const std::string & name() const override
Retrieve name of the service.
Definition Service.cpp:333
StatusCode initialize() override
Definition Service.cpp:118
Small smart pointer class with automatic reference counting for IInterface.
Definition SmartIF.h:28
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
bool isFailure() const
Definition StatusCode.h:129
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
Base class used to extend a class implementing other interfaces.
Definition extends.h:19
constexpr int SignalOffset
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1
StatusCode setAppReturnCode(SmartIF< IProperty > &appmgr, int value, bool force=false)
Set the application return code.