| The Gaudi Framework v27r1

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

IncidentSvc.cpp
Go to the documentation of this file.
1 #ifdef _WIN32
2 // ============================================================================
3 // Avoid conflicts between windows and the message service.
4 // ============================================================================
5 #define NOMSG
6 #define NOGDI
7 #endif
8 // ============================================================================
9 // Include Files
10 // ============================================================================
11 #include <functional>
12 #include "GaudiKernel/MsgStream.h"
13 #include "GaudiKernel/ISvcLocator.h"
14 #include "GaudiKernel/SmartIF.h"
15 #include "GaudiKernel/IIncidentListener.h"
16 #include "GaudiKernel/Incident.h"
17 #include "GaudiKernel/GaudiException.h"
18 #include "GaudiKernel/LockedChrono.h"
19 #include "GaudiKernel/AppReturnCode.h"
20 // ============================================================================
21 // Local
22 // ============================================================================
23 #include "IncidentSvc.h"
24 // ============================================================================
25 // Instantiation of a static factory class used by clients to create
26 // instances of this service
27 DECLARE_COMPONENT(IncidentSvc)
28 // ============================================================================
29 namespace
30 {
31 // ==========================================================================
32 static const std::string s_unknown = "<unknown>" ;
33 // Helper to get the name of the listener
34 inline const std::string& getListenerName ( IIncidentListener* lis )
35 {
36 SmartIF<INamedInterface> iNamed(lis);
37 return iNamed ? iNamed->name() : s_unknown ;
38 }
39 // ==========================================================================
40 }
41
42 #define ON_DEBUG if (msgLevel(MSG::DEBUG))
43 #define ON_VERBOSE if (msgLevel(MSG::VERBOSE))
44
45 #define DEBMSG ON_DEBUG debug()
46 #define VERMSG ON_VERBOSE verbose()
47
48 // ============================================================================
49 // Constructors and Destructors
50 // ============================================================================
51 IncidentSvc::IncidentSvc( const std::string& name, ISvcLocator* svc )
52 : base_class(name, svc)
53 {}
54 // ============================================================================
55 IncidentSvc::~IncidentSvc()
56 {
57 std::unique_lock<std::recursive_mutex> lock(m_listenerMapMutex);
58 }
59 // ============================================================================
60 // Inherited Service overrides:
61 // ============================================================================
62 StatusCode IncidentSvc::initialize()
63 {
64 // initialize the Service Base class
65 StatusCode sc = Service::initialize();
66 if ( sc.isFailure() ) return sc;
67
68 m_currentIncidentType = nullptr;
69
70 // set my own (IncidentSvc) properties via the jobOptionService
71 sc = setProperties();
72 if ( UNLIKELY(sc.isFailure()) )
73 {
74 error() << "Could not set my properties" << endmsg;
75 return sc;
76 }
77 return StatusCode::SUCCESS;
78 }
79 // ============================================================================
80 StatusCode IncidentSvc::finalize()
81 {
82 DEBMSG << m_timer.outputUserTime( "Incident timing: Mean(+-rms)/Min/Max:%3%(+-%4%)/%6%/%7%[ms] " , System::milliSec )
83 << m_timer.outputUserTime ( "Total:%2%[s]" , System::Sec ) << endmsg ;
84
85 // Finalize this specific service
86 StatusCode sc = Service::finalize();
87 if ( UNLIKELY(sc.isFailure()) ) { return sc; }
88
89 return StatusCode::SUCCESS;
90 }
91 // ============================================================================
92 // Inherited IIncidentSvc overrides:
93 // ============================================================================
94 void IncidentSvc::addListener ( IIncidentListener* lis ,
95 const std::string& type ,
96 long prio, bool rethrow, bool singleShot)
97 {
98 static const std::string all{ "ALL" };
99 std::unique_lock<std::recursive_mutex> lock(m_listenerMapMutex);
100
101 const std::string& ltype = ( !type.empty() ? type : all );
102
103 // find if the type already exists
104 auto itMap = m_listenerMap.find( ltype );
105 if( itMap == m_listenerMap.end() ) {
106 // if not found, create and insert now a list of listeners
107 auto p = m_listenerMap.insert( { ltype, std::unique_ptr<ListenerList>( new ListenerList() ) } );
108 if ( !p.second ) { /* OOPS */ }
109 itMap = p.first;
110 }
111 auto& llist = *itMap->second;
112 // add Listener ordered by priority -- higher priority first,
113 // and then add behind listeneres with the same priority
114 // -- so we skip over all items with higher or same priority
115 auto i = std::partition_point( std::begin(llist),std::end(llist),
116 [&](const Listener& j) { return j.priority >= prio; } );
117 // We insert before the current position
118 DEBMSG << "Adding [" << type << "] listener '" << getListenerName(lis)
119 << "' with priority " << prio << endmsg;
120 llist.emplace(i, lis, prio, rethrow, singleShot);
121 }
122 // ============================================================================
123 IncidentSvc::ListenerMap::iterator
124 IncidentSvc::removeListenerFromList(ListenerMap::iterator i,
125 IIncidentListener* item,
126 bool scheduleRemoval )
127 {
128 auto match = [&](ListenerList::const_reference j )
129 { return !item || item == j.iListener; };
130
131 auto& c = *(i->second);
132 if (!scheduleRemoval) {
133 ON_DEBUG std::for_each( std::begin(c), std::end(c),
134 [&](ListenerList::const_reference j) {
135 if (match(j)) debug() << "Removing [" << i->first << "] listener '"
136 << getListenerName(j.iListener) << "'" << endmsg;
137 });
138 c.erase( std::remove_if( std::begin(c), std::end(c), match ),
139 std::end(c) );
140 } else {
141 std::for_each( std::begin(c), std::end(c), [&](Listener& i) {
142 if (match(i)) i.singleShot = true; // will trigger removal as soon as it is safe
143 });
144 }
145 return c.empty() ? m_listenerMap.erase(i) : std::next(i);
146 }
147 // ============================================================================
148 void IncidentSvc::removeListener( IIncidentListener* lis ,
149 const std::string& type )
150 {
151 std::unique_lock<std::recursive_mutex> lock(m_listenerMapMutex);
152
153 bool scheduleForRemoval = ( m_currentIncidentType
154 && type == *m_currentIncidentType );
155 if( type.empty() ) {
156 auto i = std::begin(m_listenerMap);
157 while ( i != std::end(m_listenerMap) ) {
158 i = removeListenerFromList( i, lis, scheduleForRemoval );
159 }
160 } else {
161 auto i = m_listenerMap.find( type );
162 if ( i != m_listenerMap.end() ) removeListenerFromList( i, lis, scheduleForRemoval );
163 }
164 }
165 // ============================================================================
166 namespace {
168 constexpr struct isSingleShot_t {
169 bool operator() (const IncidentSvc::Listener& l) const
170 { return l.singleShot; }
171 } isSingleShot {};
172 }
173 // ============================================================================
174 void IncidentSvc::i_fireIncident( const Incident& incident ,
175 const std::string& listenerType )
176 {
177
178 std::unique_lock<std::recursive_mutex> lock(m_listenerMapMutex);
179
180 // Wouldn't it be better to write a small 'ReturnCode' service which
181 // looks for these 'special' incidents and does whatever needs to
182 // be done instead of making a special case here?
183
184 // Special case: FailInputFile incident must set the application return code
185 if ( incident.type() == IncidentType::FailInputFile ||
186 incident.type() == IncidentType::CorruptedInputFile ) {
187 auto appmgr = serviceLocator()->as<IProperty>();
188 Gaudi::setAppReturnCode(appmgr,
189 incident.type() == IncidentType::FailInputFile ?
190 Gaudi::ReturnCode::FailInput :
191 Gaudi::ReturnCode::CorruptedInput
192 ).ignore();
193 }
194
195 auto ilisteners = m_listenerMap.find( listenerType );
196 if ( m_listenerMap.end() == ilisteners ) return;
197
198 // setting this pointer will avoid that a call to removeListener() during
199 // the loop triggers a segfault
200 m_currentIncidentType = &incident.type();
201
202 bool firedSingleShot = false;
203
204 auto& listeners = *ilisteners->second;
205
206 for( auto& listener : listeners )
207 {
208
209 VERMSG << "Calling '" << getListenerName(listener.iListener)
210 << "' for incident [" << incident.type() << "]" << endmsg;
211
212 // handle exceptions if they occur
213 try {
214 listener.iListener->handle(incident);
215 }
216 catch( const GaudiException& exc ) {
217 error() << "Exception with tag=" << exc.tag() << " is caught"
218 " handling incident" << m_currentIncidentType << endmsg;
219 error() << exc << endmsg;
220 if ( listener.rethrow ) { throw exc; }
221 }
222 catch( const std::exception& exc ) {
223 error() << "Standard std::exception is caught"
224 " handling incident" << m_currentIncidentType << endmsg;
225 error() << exc.what() << endmsg;
226 if ( listener.rethrow ) { throw exc; }
227 }
228 catch(...) {
229 error() << "UNKNOWN Exception is caught"
230 " handling incident" << m_currentIncidentType << endmsg;
231 if ( listener.rethrow ) { throw; }
232 }
233 // check wheter one of the listeners is singleShot
234 firedSingleShot |= listener.singleShot;
235 }
236 if (firedSingleShot) {
237 // remove all the singleshot listeners that got there shot...
238 listeners.erase( std::remove_if( std::begin(listeners),std::end(listeners), isSingleShot ),
239 std::end(listeners) ) ;
240 if (listeners.empty()) m_listenerMap.erase(ilisteners);
241 }
242
243 m_currentIncidentType = nullptr;
244 }
245 // ============================================================================
246 void IncidentSvc::fireIncident( const Incident& incident )
247 {
248
249 Gaudi::Utils::LockedChrono timer ( m_timer , m_timerLock ) ;
250
251 // Call specific listeners
252 i_fireIncident(incident, incident.type());
253 // Try listeners registered for ALL incidents
254 if ( incident.type() != "ALL" ){ // avoid double calls if somebody fires the incident "ALL"
255 i_fireIncident(incident, "ALL");
256 }
257 }
258
259 // ============================================================================
260 void
261 IncidentSvc::getListeners(std::vector<IIncidentListener*>& l,
262 const std::string& type) const
263 {
264 static const std::string ALL { "ALL" };
265 std::unique_lock<std::recursive_mutex> lock(m_listenerMapMutex);
266
267 const std::string& ltype = ( !type.empty() ? type : ALL );
268
269 l.clear();
270 auto i = m_listenerMap.find( ltype );
271 if (i != m_listenerMap.end()) {
272 l.reserve(i->second->size());
273 std::transform( std::begin(*i->second), std::end(*i->second),
274 std::back_inserter(l),
275 [](const Listener& j) { return j.iListener; });
276 }
277 }
278
279 // ============================================================================
280 // The END
281 // ============================================================================
UNLIKELY
#define UNLIKELY(x)
Definition: Kernel.h:126
Service::initialize
StatusCode initialize() override
Definition: Service.cpp:68
SmartIF< INamedInterface >
Service::serviceLocator
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition: Service.cpp:324
GaudiKernel.Constants.ALL
int ALL
message levels --------------------------------------------------------—
Definition: Constants.py:11
IncidentSvc::m_timer
ChronoEntity m_timer
timer & it's lock
Definition: IncidentSvc.h:97
std::string::empty
T empty(T...args)
GaudiException
Define general base for Gaudi exception.
Definition: GaudiException.h:23
ISvcLocator
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
Incident::type
const std::string & type() const
Access to the incident type.
Definition: Incident.h:41
gaudiComponentHelp.name
name
Definition: gaudiComponentHelp.py:28
IncidentSvc::finalize
StatusCode finalize() override
Definition: IncidentSvc.cpp:80
Service::finalize
StatusCode finalize() override
Definition: Service.cpp:193
MsgStream.h
std::partition_point
T partition_point(T...args)
IncidentSvc::m_timerLock
bool m_timerLock
Definition: IncidentSvc.h:98
IncidentSvc::addListener
void addListener(IIncidentListener *lis, const std::string &type="", long priority=0, bool rethrow=false, bool singleShot=false) override
Definition: IncidentSvc.cpp:94
gaudirun.c
tuple c
Definition: gaudirun.py:391
ON_DEBUG
#define ON_DEBUG
Definition: IncidentSvc.cpp:42
IncidentSvc::removeListenerFromList
ListenerMap::iterator removeListenerFromList(ListenerMap::iterator, IIncidentListener *item, bool scheduleRemoval)
Definition: IncidentSvc.cpp:124
std::end
T end(T...args)
IncidentSvc::Listener::singleShot
bool singleShot
Definition: IncidentSvc.h:42
ISvcLocator::as
SmartIF< IFace > as()
Definition: ISvcLocator.h:106
System::milliSec
Definition: Timing.h:51
std::remove_if
T remove_if(T...args)
merge_files.sc
int sc
Definition: merge_files.py:167
DEBMSG
#define DEBMSG
Definition: IncidentSvc.cpp:45
StatusCode::isFailure
bool isFailure() const
Test for a status code of FAILURE.
Definition: StatusCode.h:86
IncidentSvc::IncidentSvc
IncidentSvc(const std::string &name, ISvcLocator *svc)
Definition: IncidentSvc.cpp:51
System::Sec
Definition: Timing.h:51
IncidentSvc::~IncidentSvc
~IncidentSvc() override
Definition: IncidentSvc.cpp:55
Gaudi::ReturnCode::CorruptedInput
constexpr int CorruptedInput
Definition: AppReturnCode.h:28
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginService.h:36
std::string
STL class.
Incident.h
CommonMessagingBase::error
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
Definition: CommonMessaging.h:118
GaudiUtils::Map::end
iterator end()
Definition: Map.h:132
gaudirun.type
string type
Definition: gaudirun.py:151
IIncidentListener
The interface implemented by any class wanting to listen to Incidents.
Definition: IIncidentListener.h:13
IncidentSvc::m_listenerMapMutex
std::recursive_mutex m_listenerMapMutex
Mutex to synchronize access to m_listenerMap.
Definition: IncidentSvc.h:94
std::exception::what
T what(T...args)
std::next
T next(T...args)
StatusCode::SUCCESS
Definition: StatusCode.h:30
StatusCode
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:26
IncidentSvc::removeListener
void removeListener(IIncidentListener *l, const std::string &type="") override
Definition: IncidentSvc.cpp:148
GaudiException.h
Gaudi::ReturnCode::FailInput
constexpr int FailInput
Definition: AppReturnCode.h:23
SmartIF.h
GaudiUtils::Map::find
iterator find(const key_type &key)
Definition: Map.h:149
IncidentSvc::Listener::priority
long priority
Definition: IncidentSvc.h:40
locker.lock
def lock(file)
Definition: locker.py:16
GaudiException::tag
virtual const std::string & tag() const
name tag for the exception, or exception type
Definition: GaudiException.h:119
IncidentSvc::initialize
StatusCode initialize() override
Definition: IncidentSvc.cpp:62
IncidentSvc::ListenerList
std::vector< Listener > ListenerList
Definition: IncidentSvc.h:50
IncidentSvc::m_currentIncidentType
const std::string * m_currentIncidentType
Incident being fired.
Definition: IncidentSvc.h:91
std::vector::clear
T clear(T...args)
std::exception
STL class.
Gaudi::setAppReturnCode
StatusCode setAppReturnCode(SmartIF< IProperty > &appmgr, int value, bool force=false)
Set the application return code.
Definition: AppReturnCode.h:50
LockedChrono.h
Service::setProperties
StatusCode setProperties()
Method for setting declared properties to the values specified for the job.
Definition: Service.cpp:363
IncidentSvc::getListeners
void getListeners(std::vector< IIncidentListener * > &lis, const std::string &type="") const override
Definition: IncidentSvc.cpp:261
gaudirun.l
dictionary l
Definition: gaudirun.py:421
AppReturnCode.h
ChronoEntity::outputUserTime
std::string outputUserTime() const
print the chrono ;
Definition: ChronoEntity.cpp:85
std::unique_lock
GaudiUtils::Map::iterator
map_type::iterator iterator
Definition: Map.h:99
std::vector
STL class.
std::unique_ptr< ListenerList >
Gaudi::Utils::LockedChrono
Helper object, useful for measurement of CPU-performance of highly-recursive structures, e.g.
Definition: LockedChrono.h:52
GaudiUtils::Map::erase
iterator erase(const_iterator pos)
Definition: Map.h:175
CommonMessagingBase::debug
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
Definition: CommonMessaging.h:127
VERMSG
#define VERMSG
Definition: IncidentSvc.cpp:46
std::begin
T begin(T...args)
IncidentSvc::i_fireIncident
void i_fireIncident(const Incident &incident, const std::string &type)
Internal function to allow incidents listening to all events.
Definition: IncidentSvc.cpp:174
std::back_inserter
T back_inserter(T...args)
Incident
Base class for all Incidents (computing events).
Definition: Incident.h:17
IncidentSvc::Listener
Definition: IncidentSvc.h:37
GaudiUtils::Map::insert
std::pair< iterator, bool > insert(ValueType &&val)
Definition: Map.h:168
ana.item
tuple item
print s1,s2
Definition: ana.py:146
CommonMessaging
Definition: CommonMessaging.h:58
IncidentSvc::fireIncident
void fireIncident(const Incident &incident) override
Definition: IncidentSvc.cpp:246
IIncidentListener.h
std::transform
T transform(T...args)
IncidentSvc::m_listenerMap
ListenerMap m_listenerMap
List of auditor names.
Definition: IncidentSvc.h:87
IncidentSvc
Default implementation of the IIncidentSvc interface.
Definition: IncidentSvc.h:33
IncidentSvc.h
IProperty
The IProperty is the basic interface for all components which have properties that can be set or get...
Definition: IProperty.h:21
std::for_each
T for_each(T...args)
ana.i
list i
Definition: ana.py:128
ISvcLocator.h
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:244
std::vector::reserve
T reserve(T...args)