Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v31r0 (aeb156f0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  static const std::string s_unknown = "<unknown>";
32  // Helper to get the name of the listener
33  inline const std::string& getListenerName( IIncidentListener* lis ) {
34  SmartIF<INamedInterface> iNamed( lis );
35  return iNamed ? iNamed->name() : s_unknown;
36  }
37  // ==========================================================================
38 } // namespace
39 
40 #define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
41 #define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
42 
43 #define DEBMSG ON_DEBUG debug()
44 #define VERMSG ON_VERBOSE verbose()
45 
46 // ============================================================================
47 // Constructors and Destructors
48 // ============================================================================
50 // ============================================================================
52 // ============================================================================
53 // Inherited Service overrides:
54 // ============================================================================
56  // initialize the Service Base class
58  if ( sc.isFailure() ) return sc;
59 
60  m_currentIncidentType = nullptr;
61 
62  // set my own (IncidentSvc) properties via the jobOptionService
63  sc = setProperties();
64  if ( UNLIKELY( sc.isFailure() ) ) {
65  error() << "Could not set my properties" << endmsg;
66  return sc;
67  }
68  return sc;
69 }
70 // ============================================================================
72  DEBMSG << m_timer.outputUserTime( "Incident timing: Mean(+-rms)/Min/Max:%3%(+-%4%)/%6%/%7%[ms] ", System::milliSec )
73  << m_timer.outputUserTime( "Total:%2%[s]", System::Sec ) << endmsg;
74 
75  {
76  // clear the local storage of allocated Incident objects.
78  for ( auto& fi : m_firedIncidents ) {
79  std::for_each( fi.second.unsafe_begin(), fi.second.unsafe_end(), []( auto i ) { delete i; } );
80  fi.second.clear();
81  }
82  m_firedIncidents.clear();
83  }
84 
85  // Finalize this specific service
86  return Service::finalize();
87 }
88 // ============================================================================
89 // Inherited IIncidentSvc overrides:
90 // ============================================================================
91 void IncidentSvc::addListener( IIncidentListener* lis, const std::string& type, long prio, bool rethrow,
92  bool singleShot ) {
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 // ============================================================================
120  auto match = [&]( ListenerList::const_reference j ) { return !item || item == j.iListener; };
121 
122  auto& c = *( i->second );
123  if ( !scheduleRemoval ) {
124  ON_DEBUG std::for_each( std::begin( c ), std::end( c ), [&]( ListenerList::const_reference j ) {
125  if ( match( j ) )
126  debug() << "Removing [" << i->first << "] listener '" << getListenerName( j.iListener ) << "'" << endmsg;
127  } );
128  c.erase( std::remove_if( std::begin( c ), std::end( c ), match ), std::end( c ) );
129  } else {
130  std::for_each( std::begin( c ), std::end( c ), [&]( Listener& i ) {
131  if ( match( i ) ) i.singleShot = true; // will trigger removal as soon as it is safe
132  } );
133  }
134  return c.empty() ? m_listenerMap.erase( i ) : std::next( i );
135 }
136 // ============================================================================
139 
140  bool scheduleForRemoval = ( m_currentIncidentType && type == *m_currentIncidentType );
141  if ( type.empty() ) {
142  auto i = std::begin( m_listenerMap );
143  while ( i != std::end( m_listenerMap ) ) { i = removeListenerFromList( i, lis, scheduleForRemoval ); }
144  } else {
145  auto i = m_listenerMap.find( type );
146  if ( i != m_listenerMap.end() ) removeListenerFromList( i, lis, scheduleForRemoval );
147  }
148 }
149 // ============================================================================
150 namespace {
152  constexpr struct isSingleShot_t {
153  bool operator()( const IncidentSvc::Listener& l ) const { return l.singleShot; }
154  } isSingleShot{};
155 } // namespace
156 // ============================================================================
157 void IncidentSvc::i_fireIncident( const Incident& incident, const std::string& listenerType ) {
158 
160 
161  // Wouldn't it be better to write a small 'ReturnCode' service which
162  // looks for these 'special' incidents and does whatever needs to
163  // be done instead of making a special case here?
164 
165  // Special case: FailInputFile incident must set the application return code
166  if ( incident.type() == IncidentType::FailInputFile || incident.type() == IncidentType::CorruptedInputFile ) {
167  auto appmgr = serviceLocator()->as<IProperty>();
168  Gaudi::setAppReturnCode( appmgr, incident.type() == IncidentType::FailInputFile
171  .ignore();
172  }
173 
174  auto ilisteners = m_listenerMap.find( listenerType );
175  if ( m_listenerMap.end() == ilisteners ) return;
176 
177  // setting this pointer will avoid that a call to removeListener() during
178  // the loop triggers a segfault
179  m_currentIncidentType = &incident.type();
180 
181  bool firedSingleShot = false;
182 
183  auto& listeners = *ilisteners->second;
184 
185  for ( auto& listener : listeners ) {
186 
187  VERMSG << "Calling '" << getListenerName( listener.iListener ) << "' for incident [" << incident.type() << "]"
188  << endmsg;
189 
190  // handle exceptions if they occur
191  try {
192  listener.iListener->handle( incident );
193  } catch ( const GaudiException& exc ) {
194  error() << "Exception with tag=" << exc.tag()
195  << " is caught"
196  " handling incident "
198  error() << exc << endmsg;
199  if ( listener.rethrow ) { throw exc; }
200  } catch ( const std::exception& exc ) {
201  error() << "Standard std::exception is caught"
202  " handling incident "
204  error() << exc.what() << endmsg;
205  if ( listener.rethrow ) { throw exc; }
206  } catch ( ... ) {
207  error() << "UNKNOWN Exception is caught"
208  " handling incident "
210  if ( listener.rethrow ) { throw; }
211  }
212  // check wheter one of the listeners is singleShot
213  firedSingleShot |= listener.singleShot;
214  }
215  if ( firedSingleShot ) {
216  // remove all the singleshot listeners that got there shot...
217  listeners.erase( std::remove_if( std::begin( listeners ), std::end( listeners ), isSingleShot ),
218  std::end( listeners ) );
219  if ( listeners.empty() ) m_listenerMap.erase( ilisteners );
220  }
221 
222  m_currentIncidentType = nullptr;
223 }
224 // ============================================================================
225 void IncidentSvc::fireIncident( const Incident& incident ) {
226 
228 
229  // Call specific listeners
230  i_fireIncident( incident, incident.type() );
231  // Try listeners registered for ALL incidents
232  if ( incident.type() != "ALL" ) { // avoid double calls if somebody fires the incident "ALL"
233  i_fireIncident( incident, "ALL" );
234  }
235 }
236 // ============================================================================
238 
239  DEBMSG << "Async incident '" << incident->type() << "' fired on context " << incident->context() << endmsg;
240  auto ctx = incident->context();
241  auto res = m_firedIncidents.insert( std::make_pair( ctx, IncQueue_t() ) );
242  res.first->second.push( incident.release() );
243 }
244 // ============================================================================
245 
247  static const std::string ALL{"ALL"};
249 
250  const std::string& ltype = ( !type.empty() ? type : ALL );
251 
252  l.clear();
253  auto i = m_listenerMap.find( ltype );
254  if ( i != m_listenerMap.end() ) {
255  l.reserve( i->second->size() );
256  std::transform( std::begin( *i->second ), std::end( *i->second ), std::back_inserter( l ),
257  []( const Listener& j ) { return j.iListener; } );
258  }
259 }
260 
261 // ============================================================================
262 
265  if ( ctx ) {
266  auto incs = m_firedIncidents.find( *ctx );
267  if ( incs != m_firedIncidents.end() ) {
268  Incident* inc( 0 );
269 
270  DEBMSG << "Collecting listeners fired on context " << *ctx << endmsg;
271  while ( incs->second.try_pop( inc ) ) {
273  getListeners( ls, inc->type() );
274  p.incidents.emplace_back( std::move( inc ) );
275  p.listeners.emplace_back( std::move( ls ) );
276  }
277  }
278  }
279  return p;
280 }
281 // ============================================================================
282 // The END
283 // ============================================================================
#define UNLIKELY(x)
Definition: Kernel.h:89
StatusCode initialize() override
Definition: Service.cpp:60
ChronoEntity m_timer
timer & it&#39;s lock
Definition: IncidentSvc.h:97
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:38
StatusCode finalize() override
Definition: IncidentSvc.cpp:71
StatusCode finalize() override
Definition: Service.cpp:164
T partition_point(T...args)
bool m_timerLock
Definition: IncidentSvc.h:98
void addListener(IIncidentListener *lis, const std::string &type="", long priority=0, bool rethrow=false, bool singleShot=false) override
Definition: IncidentSvc.cpp:91
#define ON_DEBUG
Definition: IncidentSvc.cpp:40
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:103
T remove_if(T...args)
#define DEBMSG
Definition: IncidentSvc.cpp:43
This class represents an entry point to all the event specific data.
Definition: EventContext.h:31
bool isFailure() const
Definition: StatusCode.h:130
IncidentSvc(const std::string &name, ISvcLocator *svc)
Definition: IncidentSvc.cpp:49
T release(T...args)
~IncidentSvc() override
Definition: IncidentSvc.cpp:51
constexpr int CorruptedInput
Definition: AppReturnCode.h:28
std::vector< std::unique_ptr< Incident > > incidents
Definition: IIncidentSvc.h:51
STL class.
#define DECLARE_COMPONENT(type)
std::pair< iterator, bool > insert(ValueType &&val)
Definition: Map.h:168
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
iterator end()
Definition: Map.h:130
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:94
T what(T...args)
T next(T...args)
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:50
void removeListener(IIncidentListener *l, const std::string &type="") override
constexpr int FailInput
Definition: AppReturnCode.h:23
iterator find(const key_type &key)
Definition: Map.h:147
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:55
std::vector< std::vector< IIncidentListener * > > listeners
Definition: IIncidentSvc.h:52
const std::string * m_currentIncidentType
Incident being fired.
Definition: IncidentSvc.h:91
T clear(T...args)
STL class.
StatusCode setAppReturnCode(SmartIF< IProperty > &appmgr, int value, bool force=false)
Set the application return code.
Definition: AppReturnCode.h:49
T move(T...args)
StatusCode setProperties()
Method for setting declared properties to the values specified for the job.
Definition: Service.cpp:280
tbb::concurrent_queue< Incident * > IncQueue_t
Definition: IncidentSvc.h:102
tbb::concurrent_unordered_map< EventContext, IncQueue_t, EventContextHash, EventContextHash > m_firedIncidents
Definition: IncidentSvc.h:103
dictionary l
Definition: gaudirun.py:517
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:50
virtual Out operator()(const vector_of_const_< In > &inputs) const =0
iterator erase(const_iterator pos)
Definition: Map.h:182
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
#define VERMSG
Definition: IncidentSvc.cpp:44
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:87
Default implementation of the IIncidentSvc interface.
Definition: IncidentSvc.h:38
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:50
T for_each(T...args)
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition: Service.cpp:277
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:192
T reserve(T...args)
T emplace_back(T...args)