The Gaudi Framework  v30r3 (a5ef0a68)
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 // ============================================================================
15 #include "GaudiKernel/Incident.h"
17 #include "GaudiKernel/MsgStream.h"
18 #include "GaudiKernel/SmartIF.h"
19 #include <functional>
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
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 // ============================================================================
52 // ============================================================================
54 // ============================================================================
55 // Inherited Service overrides:
56 // ============================================================================
58 {
59  // initialize the Service Base class
61  if ( sc.isFailure() ) return sc;
62 
63  m_currentIncidentType = nullptr;
64 
65  // set my own (IncidentSvc) properties via the jobOptionService
66  sc = setProperties();
67  if ( UNLIKELY( sc.isFailure() ) ) {
68  error() << "Could not set my properties" << endmsg;
69  return sc;
70  }
71  return StatusCode::SUCCESS;
72 }
73 // ============================================================================
75 {
76  DEBMSG << m_timer.outputUserTime( "Incident timing: Mean(+-rms)/Min/Max:%3%(+-%4%)/%6%/%7%[ms] ", System::milliSec )
77  << m_timer.outputUserTime( "Total:%2%[s]", System::Sec ) << endmsg;
78 
79  // Finalize this specific service
81  if ( UNLIKELY( sc.isFailure() ) ) {
82  return sc;
83  }
84 
85  return StatusCode::SUCCESS;
86 }
87 // ============================================================================
88 // Inherited IIncidentSvc overrides:
89 // ============================================================================
90 void IncidentSvc::addListener( IIncidentListener* lis, const std::string& type, long prio, bool rethrow,
91  bool singleShot )
92 {
93  static const std::string all{"ALL"};
95 
96  const std::string& ltype = ( !type.empty() ? type : all );
97 
98  // find if the type already exists
99  auto itMap = m_listenerMap.find( ltype );
100  if ( itMap == m_listenerMap.end() ) {
101  // if not found, create and insert now a list of listeners
102  auto p = m_listenerMap.insert( {ltype, std::make_unique<ListenerList>()} );
103  if ( !p.second ) { /* OOPS */
104  }
105  itMap = p.first;
106  }
107  auto& llist = *itMap->second;
108  // add Listener ordered by priority -- higher priority first,
109  // and then add behind listeneres with the same priority
110  // -- so we skip over all items with higher or same priority
111  auto i = std::partition_point( std::begin( llist ), std::end( llist ),
112  [&]( const Listener& j ) { return j.priority >= prio; } );
113  // We insert before the current position
114  DEBMSG << "Adding [" << type << "] listener '" << getListenerName( lis ) << "' with priority " << prio << endmsg;
115  llist.emplace( i, lis, prio, rethrow, singleShot );
116 }
117 // ============================================================================
119  IIncidentListener* item, bool scheduleRemoval )
120 {
121  auto match = [&]( ListenerList::const_reference j ) { return !item || item == j.iListener; };
122 
123  auto& c = *( i->second );
124  if ( !scheduleRemoval ) {
125  ON_DEBUG std::for_each( std::begin( c ), std::end( c ), [&]( ListenerList::const_reference j ) {
126  if ( match( j ) )
127  debug() << "Removing [" << i->first << "] listener '" << getListenerName( j.iListener ) << "'" << endmsg;
128  } );
129  c.erase( std::remove_if( std::begin( c ), std::end( c ), match ), std::end( c ) );
130  } else {
131  std::for_each( std::begin( c ), std::end( c ), [&]( Listener& i ) {
132  if ( match( i ) ) i.singleShot = true; // will trigger removal as soon as it is safe
133  } );
134  }
135  return c.empty() ? m_listenerMap.erase( i ) : std::next( i );
136 }
137 // ============================================================================
139 {
141 
142  bool scheduleForRemoval = ( m_currentIncidentType && type == *m_currentIncidentType );
143  if ( type.empty() ) {
144  auto i = std::begin( m_listenerMap );
145  while ( i != std::end( m_listenerMap ) ) {
146  i = removeListenerFromList( i, lis, scheduleForRemoval );
147  }
148  } else {
149  auto i = m_listenerMap.find( type );
150  if ( i != m_listenerMap.end() ) removeListenerFromList( i, lis, scheduleForRemoval );
151  }
152 }
153 // ============================================================================
154 namespace
155 {
157  constexpr struct isSingleShot_t {
158  bool operator()( const IncidentSvc::Listener& l ) const { return l.singleShot; }
159  } isSingleShot{};
160 }
161 // ============================================================================
162 void IncidentSvc::i_fireIncident( const Incident& incident, const std::string& listenerType )
163 {
164 
166 
167  // Wouldn't it be better to write a small 'ReturnCode' service which
168  // looks for these 'special' incidents and does whatever needs to
169  // be done instead of making a special case here?
170 
171  // Special case: FailInputFile incident must set the application return code
172  if ( incident.type() == IncidentType::FailInputFile || incident.type() == IncidentType::CorruptedInputFile ) {
173  auto appmgr = serviceLocator()->as<IProperty>();
174  Gaudi::setAppReturnCode( appmgr, incident.type() == IncidentType::FailInputFile
177  .ignore();
178  }
179 
180  auto ilisteners = m_listenerMap.find( listenerType );
181  if ( m_listenerMap.end() == ilisteners ) return;
182 
183  // setting this pointer will avoid that a call to removeListener() during
184  // the loop triggers a segfault
185  m_currentIncidentType = &incident.type();
186 
187  bool firedSingleShot = false;
188 
189  auto& listeners = *ilisteners->second;
190 
191  for ( auto& listener : listeners ) {
192 
193  VERMSG << "Calling '" << getListenerName( listener.iListener ) << "' for incident [" << incident.type() << "]"
194  << endmsg;
195 
196  // handle exceptions if they occur
197  try {
198  listener.iListener->handle( incident );
199  } catch ( const GaudiException& exc ) {
200  error() << "Exception with tag=" << exc.tag() << " is caught"
201  " handling incident "
203  error() << exc << endmsg;
204  if ( listener.rethrow ) {
205  throw exc;
206  }
207  } catch ( const std::exception& exc ) {
208  error() << "Standard std::exception is caught"
209  " handling incident "
211  error() << exc.what() << endmsg;
212  if ( listener.rethrow ) {
213  throw exc;
214  }
215  } catch ( ... ) {
216  error() << "UNKNOWN Exception is caught"
217  " handling incident "
219  if ( listener.rethrow ) {
220  throw;
221  }
222  }
223  // check wheter one of the listeners is singleShot
224  firedSingleShot |= listener.singleShot;
225  }
226  if ( firedSingleShot ) {
227  // remove all the singleshot listeners that got there shot...
228  listeners.erase( std::remove_if( std::begin( listeners ), std::end( listeners ), isSingleShot ),
229  std::end( listeners ) );
230  if ( listeners.empty() ) m_listenerMap.erase( ilisteners );
231  }
232 
233  m_currentIncidentType = nullptr;
234 }
235 // ============================================================================
236 void IncidentSvc::fireIncident( const Incident& incident )
237 {
238 
240 
241  // Call specific listeners
242  i_fireIncident( incident, incident.type() );
243  // Try listeners registered for ALL incidents
244  if ( incident.type() != "ALL" ) { // avoid double calls if somebody fires the incident "ALL"
245  i_fireIncident( incident, "ALL" );
246  }
247 }
248 // ============================================================================
250 {
251 
252  DEBMSG << "Async incident '" << incident->type() << "' fired on context " << incident->context() << endmsg;
253  auto ctx = incident->context();
254  auto res = m_firedIncidents.insert( std::make_pair( ctx, IncQueue_t() ) );
255  res.first->second.push( incident.release() );
256 }
257 // ============================================================================
258 
260 {
261  static const std::string ALL{"ALL"};
263 
264  const std::string& ltype = ( !type.empty() ? type : ALL );
265 
266  l.clear();
267  auto i = m_listenerMap.find( ltype );
268  if ( i != m_listenerMap.end() ) {
269  l.reserve( i->second->size() );
270  std::transform( std::begin( *i->second ), std::end( *i->second ), std::back_inserter( l ),
271  []( const Listener& j ) { return j.iListener; } );
272  }
273 }
274 
275 // ============================================================================
276 
278 {
280  if ( ctx ) {
281  auto incs = m_firedIncidents.find( *ctx );
282  if ( incs != m_firedIncidents.end() ) {
283  Incident* inc( 0 );
284 
285  DEBMSG << "Collecting listeners fired on context " << *ctx << endmsg;
286  while ( incs->second.try_pop( inc ) ) {
288  getListeners( ls, inc->type() );
289  p.incidents.emplace_back( std::move( inc ) );
290  p.listeners.emplace_back( std::move( ls ) );
291  }
292  }
293  }
294  return p;
295 }
296 // ============================================================================
297 // The END
298 // ============================================================================
#define UNLIKELY(x)
Definition: Kernel.h:122
StatusCode initialize() override
Definition: Service.cpp:63
ChronoEntity m_timer
timer & it&#39;s lock
Definition: IncidentSvc.h:99
T empty(T...args)
Define general base for Gaudi exception.
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
const std::string & type() const
Access to the incident type.
Definition: Incident.h:41
StatusCode finalize() override
Definition: IncidentSvc.cpp:74
StatusCode finalize() override
Definition: Service.cpp:173
T partition_point(T...args)
bool m_timerLock
Definition: IncidentSvc.h:100
void addListener(IIncidentListener *lis, const std::string &type="", long priority=0, bool rethrow=false, bool singleShot=false) override
Definition: IncidentSvc.cpp:90
#define ON_DEBUG
Definition: IncidentSvc.cpp:42
IIncidentSvc::IncidentPack getIncidents(const EventContext *ctx) override
ListenerMap::iterator removeListenerFromList(ListenerMap::iterator, IIncidentListener *item, bool scheduleRemoval)
T end(T...args)
SmartIF< IFace > as()
Definition: ISvcLocator.h:109
T remove_if(T...args)
#define DEBMSG
Definition: IncidentSvc.cpp:45
This class represents an entry point to all the event specific data.
Definition: EventContext.h:24
bool isFailure() const
Definition: StatusCode.h:139
IncidentSvc(const std::string &name, ISvcLocator *svc)
Definition: IncidentSvc.cpp:51
T release(T...args)
~IncidentSvc() override
Definition: IncidentSvc.cpp:53
constexpr int CorruptedInput
Definition: AppReturnCode.h:30
std::vector< std::unique_ptr< Incident > > incidents
Definition: IIncidentSvc.h:53
STL class.
#define DECLARE_COMPONENT(type)
std::pair< iterator, bool > insert(ValueType &&val)
Definition: Map.h:174
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
iterator end()
Definition: Map.h:134
The interface implemented by any class wanting to listen to Incidents.
std::recursive_mutex m_listenerMapMutex
Mutex to synchronize access to m_listenerMap.
Definition: IncidentSvc.h:96
T what(T...args)
T next(T...args)
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:51
void removeListener(IIncidentListener *l, const std::string &type="") override
constexpr int FailInput
Definition: AppReturnCode.h:25
iterator find(const key_type &key)
Definition: Map.h:151
T make_pair(T...args)
virtual const std::string & tag() const
name tag for the exception, or exception type
StatusCode initialize() override
Definition: IncidentSvc.cpp:57
std::vector< std::vector< IIncidentListener * > > listeners
Definition: IIncidentSvc.h:54
const std::string * m_currentIncidentType
Incident being fired.
Definition: IncidentSvc.h:93
T clear(T...args)
STL class.
StatusCode setAppReturnCode(SmartIF< IProperty > &appmgr, int value, bool force=false)
Set the application return code.
Definition: AppReturnCode.h:51
T move(T...args)
StatusCode setProperties()
Method for setting declared properties to the values specified for the job.
Definition: Service.cpp:294
constexpr static const auto SUCCESS
Definition: StatusCode.h:87
tbb::concurrent_queue< Incident * > IncQueue_t
Definition: IncidentSvc.h:104
tbb::concurrent_unordered_map< EventContext, IncQueue_t, EventContextHash, EventContextHash > m_firedIncidents
Definition: IncidentSvc.h:105
dictionary l
Definition: gaudirun.py:440
std::string outputUserTime() const
print the chrono ;
void getListeners(std::vector< IIncidentListener * > &lis, const std::string &type="") const override
STL class.
Helper object, useful for measurement of CPU-performance of highly-recursive structures, e.g.
Definition: LockedChrono.h:52
virtual Out operator()(const vector_of_const_< In > &inputs) const =0
iterator erase(const_iterator pos)
Definition: Map.h:192
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
#define VERMSG
Definition: IncidentSvc.cpp:46
T begin(T...args)
void i_fireIncident(const Incident &incident, const std::string &type)
Internal function to allow incidents listening to all events.
T back_inserter(T...args)
Base class for all Incidents (computing events).
Definition: Incident.h:17
void fireIncident(const Incident &incident) override
T transform(T...args)
ListenerMap m_listenerMap
List of auditor names.
Definition: IncidentSvc.h:89
Default implementation of the IIncidentSvc interface.
Definition: IncidentSvc.h:37
The IProperty is the basic interface for all components which have properties that can be set or get...
Definition: IProperty.h:20
EventContext context() const
Access to the EventContext of the source of the incident.
Definition: Incident.h:53
T for_each(T...args)
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition: Service.cpp:291
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:209
T reserve(T...args)
T emplace_back(T...args)