The Gaudi Framework  v33r0 (d5ea422b)
IncidentSvc.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 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 #ifdef _WIN32
12 // ============================================================================
13 // Avoid conflicts between windows and the message service.
14 // ============================================================================
15 # define NOMSG
16 # define NOGDI
17 #endif
18 // ============================================================================
19 // Include Files
20 // ============================================================================
25 #include "GaudiKernel/Incident.h"
27 #include "GaudiKernel/MsgStream.h"
28 #include "GaudiKernel/SmartIF.h"
29 #include <functional>
30 // ============================================================================
31 // Local
32 // ============================================================================
33 #include "IncidentSvc.h"
34 // ============================================================================
35 // Instantiation of a static factory class used by clients to create
36 // instances of this service
38 // ============================================================================
39 namespace {
40  // ==========================================================================
41  static const std::string s_unknown = "<unknown>";
42  // Helper to get the name of the listener
43  inline const std::string& getListenerName( IIncidentListener* lis ) {
44  SmartIF<INamedInterface> iNamed( lis );
45  return iNamed ? iNamed->name() : s_unknown;
46  }
47  // ==========================================================================
48 } // namespace
49 
50 #define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
51 #define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
52 
53 #define DEBMSG ON_DEBUG debug()
54 #define VERMSG ON_VERBOSE verbose()
55 
56 // ============================================================================
57 // Constructors and Destructors
58 // ============================================================================
60 // ============================================================================
62 // ============================================================================
63 // Inherited Service overrides:
64 // ============================================================================
66  // initialize the Service Base class
68  if ( sc.isFailure() ) return sc;
69 
70  m_currentIncidentType = nullptr;
71 
72  // set my own (IncidentSvc) properties via the jobOptionService
73  sc = setProperties();
74  if ( UNLIKELY( sc.isFailure() ) ) {
75  error() << "Could not set my properties" << endmsg;
76  return sc;
77  }
78  return sc;
79 }
80 // ============================================================================
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  {
86  // clear the local storage of allocated Incident objects.
88  for ( auto& fi : m_firedIncidents ) {
89  std::for_each( fi.second.unsafe_begin(), fi.second.unsafe_end(), []( auto i ) { delete i; } );
90  fi.second.clear();
91  }
92  m_firedIncidents.clear();
93  }
94 
95  // Finalize this specific service
96  return Service::finalize();
97 }
98 // ============================================================================
99 // Inherited IIncidentSvc overrides:
100 // ============================================================================
101 void IncidentSvc::addListener( IIncidentListener* lis, const std::string& type, long prio, bool rethrow,
102  bool singleShot ) {
103  static const std::string all{"ALL"};
105 
106  const std::string& ltype = ( !type.empty() ? type : all );
107 
108  // find if the type already exists
109  auto itMap = m_listenerMap.find( ltype );
110  if ( itMap == m_listenerMap.end() ) {
111  // if not found, create and insert now a list of listeners
112  auto p = m_listenerMap.insert( {ltype, std::make_unique<ListenerList>()} );
113  if ( !p.second ) { /* OOPS */
114  }
115  itMap = p.first;
116  }
117  auto& llist = *itMap->second;
118  // add Listener ordered by priority -- higher priority first,
119  // and then add behind listeneres with the same priority
120  // -- so we skip over all items with higher or same priority
121  auto i = std::partition_point( std::begin( llist ), std::end( llist ),
122  [&]( const Listener& j ) { return j.priority >= prio; } );
123  // We insert before the current position
124  DEBMSG << "Adding [" << type << "] listener '" << getListenerName( lis ) << "' with priority " << prio << endmsg;
125  llist.emplace( i, lis, prio, rethrow, singleShot );
126 }
127 // ============================================================================
129 IncidentSvc::removeListenerFromList( ListenerMap::iterator i, IIncidentListener* item, bool scheduleRemoval ) {
130  auto match = [&]( ListenerList::const_reference j ) { return !item || item == j.iListener; };
131 
132  auto& c = *( i->second );
133  if ( !scheduleRemoval ) {
134  ON_DEBUG std::for_each( std::begin( c ), std::end( c ), [&]( ListenerList::const_reference j ) {
135  if ( match( j ) )
136  debug() << "Removing [" << i->first << "] listener '" << getListenerName( j.iListener ) << "'" << endmsg;
137  } );
138  c.erase( std::remove_if( std::begin( c ), std::end( c ), match ), std::end( c ) );
139  } else {
140  std::for_each( std::begin( c ), std::end( c ), [&]( Listener& i ) {
141  if ( match( i ) ) i.singleShot = true; // will trigger removal as soon as it is safe
142  } );
143  }
144  return c.empty() ? m_listenerMap.erase( i ) : std::next( i );
145 }
146 // ============================================================================
149 
150  bool scheduleForRemoval = ( m_currentIncidentType && type == *m_currentIncidentType );
151  if ( type.empty() ) {
152  auto i = std::begin( m_listenerMap );
153  while ( i != std::end( m_listenerMap ) ) { i = removeListenerFromList( i, lis, scheduleForRemoval ); }
154  } else {
155  auto i = m_listenerMap.find( type );
156  if ( i != m_listenerMap.end() ) removeListenerFromList( i, lis, scheduleForRemoval );
157  }
158 }
159 // ============================================================================
160 namespace {
162  constexpr struct isSingleShot_t {
163  bool operator()( const IncidentSvc::Listener& l ) const { return l.singleShot; }
164  } isSingleShot{};
165 } // namespace
166 // ============================================================================
167 void IncidentSvc::i_fireIncident( const Incident& incident, const std::string& listenerType ) {
168 
170 
171  // Wouldn't it be better to write a small 'ReturnCode' service which
172  // looks for these 'special' incidents and does whatever needs to
173  // be done instead of making a special case here?
174 
175  // Special case: FailInputFile incident must set the application return code
176  if ( incident.type() == IncidentType::FailInputFile || incident.type() == IncidentType::CorruptedInputFile ) {
177  auto appmgr = serviceLocator()->as<IProperty>();
178  Gaudi::setAppReturnCode( appmgr, incident.type() == IncidentType::FailInputFile
181  .ignore();
182  }
183 
184  auto ilisteners = m_listenerMap.find( listenerType );
185  if ( m_listenerMap.end() == ilisteners ) return;
186 
187  // setting this pointer will avoid that a call to removeListener() during
188  // the loop triggers a segfault
189  m_currentIncidentType = &incident.type();
190 
191  bool firedSingleShot = false;
192 
193  auto& listeners = *ilisteners->second;
194 
195  for ( auto& listener : listeners ) {
196 
197  VERMSG << "Calling '" << getListenerName( listener.iListener ) << "' for incident [" << incident.type() << "]"
198  << endmsg;
199 
200  // handle exceptions if they occur
201  try {
202  listener.iListener->handle( incident );
203  } catch ( const GaudiException& exc ) {
204  error() << "Exception with tag=" << exc.tag()
205  << " is caught"
206  " handling incident "
208  error() << exc << endmsg;
209  if ( listener.rethrow ) { throw exc; }
210  } catch ( const std::exception& exc ) {
211  error() << "Standard std::exception is caught"
212  " handling incident "
214  error() << exc.what() << endmsg;
215  if ( listener.rethrow ) { throw exc; }
216  } catch ( ... ) {
217  error() << "UNKNOWN Exception is caught"
218  " handling incident "
220  if ( listener.rethrow ) { throw; }
221  }
222  // check wheter one of the listeners is singleShot
223  firedSingleShot |= listener.singleShot;
224  }
225  if ( firedSingleShot ) {
226  // remove all the singleshot listeners that got there shot...
227  listeners.erase( std::remove_if( std::begin( listeners ), std::end( listeners ), isSingleShot ),
228  std::end( listeners ) );
229  if ( listeners.empty() ) m_listenerMap.erase( ilisteners );
230  }
231 
232  m_currentIncidentType = nullptr;
233 }
234 // ============================================================================
235 void IncidentSvc::fireIncident( const Incident& incident ) {
236 
238 
239  // Call specific listeners
240  i_fireIncident( incident, incident.type() );
241  // Try listeners registered for ALL incidents
242  if ( incident.type() != "ALL" ) { // avoid double calls if somebody fires the incident "ALL"
243  i_fireIncident( incident, "ALL" );
244  }
245 }
246 // ============================================================================
248 
249  DEBMSG << "Async incident '" << incident->type() << "' fired on context " << incident->context() << endmsg;
250  auto ctx = incident->context();
251  auto res = m_firedIncidents.insert( std::make_pair( ctx, IncQueue_t() ) );
252  res.first->second.push( incident.release() );
253 }
254 // ============================================================================
255 
257  static const std::string ALL{"ALL"};
259 
260  const std::string& ltype = ( !type.empty() ? type : ALL );
261 
262  l.clear();
263  auto i = m_listenerMap.find( ltype );
264  if ( i != m_listenerMap.end() ) {
265  l.reserve( i->second->size() );
266  std::transform( std::begin( *i->second ), std::end( *i->second ), std::back_inserter( l ),
267  []( const Listener& j ) { return j.iListener; } );
268  }
269 }
270 
271 // ============================================================================
272 
275  if ( ctx ) {
276  auto incs = m_firedIncidents.find( *ctx );
277  if ( incs != m_firedIncidents.end() ) {
278  Incident* inc( 0 );
279 
280  DEBMSG << "Collecting listeners fired on context " << *ctx << endmsg;
281  while ( incs->second.try_pop( inc ) ) {
283  getListeners( ls, inc->type() );
284  p.incidents.emplace_back( std::move( inc ) );
285  p.listeners.emplace_back( std::move( ls ) );
286  }
287  }
288  }
289  return p;
290 }
291 // ============================================================================
292 // The END
293 // ============================================================================
#define UNLIKELY(x)
Definition: Kernel.h:106
StatusCode initialize() override
Definition: Service.cpp:70
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition: Service.cpp:287
ChronoEntity m_timer
timer & it's lock
Definition: IncidentSvc.h:107
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:35
StatusCode finalize() override
Definition: IncidentSvc.cpp:81
StatusCode finalize() override
Definition: Service.cpp:174
T partition_point(T... args)
const std::string & type() const
Access to the incident type.
Definition: Incident.h:48
bool m_timerLock
Definition: IncidentSvc.h:108
void addListener(IIncidentListener *lis, const std::string &type="", long priority=0, bool rethrow=false, bool singleShot=false) override
#define ON_DEBUG
Definition: IncidentSvc.cpp:50
IIncidentSvc::IncidentPack getIncidents(const EventContext *ctx) override
virtual const std::string & tag() const
name tag for the exception, or exception type
ListenerMap::iterator removeListenerFromList(ListenerMap::iterator, IIncidentListener *item, bool scheduleRemoval)
T end(T... args)
SmartIF< IFace > as()
Definition: ISvcLocator.h:113
T remove_if(T... args)
#define DEBMSG
Definition: IncidentSvc.cpp:53
This class represents an entry point to all the event specific data.
Definition: EventContext.h:34
EventContext context() const
Access to the EventContext of the source of the incident.
Definition: Incident.h:60
IncidentSvc(const std::string &name, ISvcLocator *svc)
Definition: IncidentSvc.cpp:59
T release(T... args)
~IncidentSvc() override
Definition: IncidentSvc.cpp:61
constexpr int CorruptedInput
Definition: AppReturnCode.h:38
std::vector< std::unique_ptr< Incident > > incidents
Definition: IIncidentSvc.h:61
STL class.
#define DECLARE_COMPONENT(type)
std::pair< iterator, bool > insert(ValueType &&val)
Definition: Map.h:178
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
iterator end()
Definition: Map.h:140
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:104
T what(T... args)
T next(T... args)
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:61
void removeListener(IIncidentListener *l, const std::string &type="") override
constexpr int FailInput
Definition: AppReturnCode.h:33
iterator find(const key_type &key)
Definition: Map.h:157
T make_pair(T... args)
StatusCode initialize() override
Definition: IncidentSvc.cpp:65
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
std::vector< std::vector< IIncidentListener * > > listeners
Definition: IIncidentSvc.h:62
const std::string * m_currentIncidentType
Incident being fired.
Definition: IncidentSvc.h:101
STL class.
StatusCode setAppReturnCode(SmartIF< IProperty > &appmgr, int value, bool force=false)
Set the application return code.
Definition: AppReturnCode.h:59
T move(T... args)
StatusCode setProperties()
Method for setting declared properties to the values specified for the job.
Definition: Service.cpp:290
void getListeners(std::vector< IIncidentListener * > &lis, const std::string &type="") const override
tbb::concurrent_queue< Incident * > IncQueue_t
Definition: IncidentSvc.h:112
tbb::concurrent_unordered_map< EventContext, IncQueue_t, EventContextHash, EventContextHash > m_firedIncidents
Definition: IncidentSvc.h:113
dictionary l
Definition: gaudirun.py:543
STL class.
Helper object, useful for measurement of CPU-performance of highly-recursive structures,...
Definition: LockedChrono.h:60
iterator erase(const_iterator pos)
Definition: Map.h:192
#define VERMSG
Definition: IncidentSvc.cpp:54
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:27
void fireIncident(const Incident &incident) override
T transform(T... args)
bool isFailure() const
Definition: StatusCode.h:141
ListenerMap m_listenerMap
List of auditor names.
Definition: IncidentSvc.h:97
Default implementation of the IIncidentSvc interface.
Definition: IncidentSvc.h:48
The IProperty is the basic interface for all components which have properties that can be set or get.
Definition: IProperty.h:30
T for_each(T... args)
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:202
std::string outputUserTime() const
print the chrono ;
T emplace_back(T... args)