The Gaudi Framework  v36r0 (4abb4d13)
IncidentSvc.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2021 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 // ============================================================================
61 IncidentSvc::~IncidentSvc() { auto lock = std::scoped_lock{m_listenerMapMutex}; }
62 // ============================================================================
64  DEBMSG << m_timer.outputUserTime( "Incident timing: Mean(+-rms)/Min/Max:%3%(+-%4%)/%6%/%7%[ms] ", System::milliSec )
65  << m_timer.outputUserTime( "Total:%2%[s]", System::Sec ) << endmsg;
66 
67  {
68  // clear the local storage of allocated Incident objects.
69  for ( auto& fi : m_firedIncidents ) {
70  std::for_each( fi.second.unsafe_begin(), fi.second.unsafe_end(), []( auto i ) { delete i; } );
71  fi.second.clear();
72  }
73  m_firedIncidents.clear();
74  }
75 
76  // Finalize this specific service
77  return Service::finalize();
78 }
79 // ============================================================================
80 // Inherited IIncidentSvc overrides:
81 // ============================================================================
82 void IncidentSvc::addListener( IIncidentListener* lis, const std::string& type, long prio, bool rethrow,
83  bool singleShot ) {
84  static const std::string all{"ALL"};
85  auto lock = std::scoped_lock{m_listenerMapMutex};
86 
87  const std::string& ltype = ( !type.empty() ? type : all );
88 
89  // find if the type already exists
90  auto itMap = m_listenerMap.find( ltype );
91  if ( itMap == m_listenerMap.end() ) {
92  // if not found, create and insert now a list of listeners
93  auto p = m_listenerMap.insert( {ltype, std::make_unique<ListenerList>()} );
94  if ( !p.second ) { /* OOPS */
95  }
96  itMap = p.first;
97  }
98  auto& llist = *itMap->second;
99  // add Listener ordered by priority -- higher priority first,
100  // and then add behind listeneres with the same priority
101  // -- so we skip over all items with higher or same priority
102  auto i = std::partition_point( std::begin( llist ), std::end( llist ),
103  [&]( const Listener& j ) { return j.priority >= prio; } );
104  // We insert before the current position
105  DEBMSG << "Adding [" << type << "] listener '" << getListenerName( lis ) << "' with priority " << prio << endmsg;
106  llist.emplace( i, std::move( IIncidentSvc::Listener{lis, prio, rethrow, singleShot} ) );
107 }
108 // ============================================================================
110 IncidentSvc::removeListenerFromList( ListenerMap::iterator i, IIncidentListener* item, bool scheduleRemoval ) {
111  auto match = [&]( ListenerList::const_reference j ) { return !item || item == j.iListener; };
112 
113  auto& c = *( i->second );
114  if ( !scheduleRemoval ) {
115  ON_DEBUG std::for_each( std::begin( c ), std::end( c ), [&]( ListenerList::const_reference j ) {
116  if ( match( j ) )
117  debug() << "Removing [" << i->first << "] listener '" << getListenerName( j.iListener ) << "'" << endmsg;
118  } );
119  c.erase( std::remove_if( std::begin( c ), std::end( c ), match ), std::end( c ) );
120  } else {
121  std::for_each( std::begin( c ), std::end( c ), [&]( Listener& i ) {
122  if ( match( i ) ) i.singleShot = true; // will trigger removal as soon as it is safe
123  } );
124  }
125  return c.empty() ? m_listenerMap.erase( i ) : std::next( i );
126 }
127 // ============================================================================
129  auto lock = std::scoped_lock{m_listenerMapMutex};
130 
131  bool scheduleForRemoval = ( m_currentIncidentType && type == *m_currentIncidentType );
132  if ( type.empty() ) {
133  auto i = std::begin( m_listenerMap );
134  while ( i != std::end( m_listenerMap ) ) { i = removeListenerFromList( i, lis, scheduleForRemoval ); }
135  } else {
136  auto i = m_listenerMap.find( type );
137  if ( i != m_listenerMap.end() ) removeListenerFromList( i, lis, scheduleForRemoval );
138  }
139 }
140 // ============================================================================
141 namespace {
143  constexpr struct isSingleShot_t {
144  bool operator()( const IncidentSvc::Listener& l ) const { return l.singleShot; }
145  } isSingleShot{};
146 } // namespace
147 // ============================================================================
148 void IncidentSvc::i_fireIncident( const Incident& incident, const std::string& listenerType ) {
149 
150  auto lock = std::scoped_lock{m_listenerMapMutex};
151 
152  // Wouldn't it be better to write a small 'ReturnCode' service which
153  // looks for these 'special' incidents and does whatever needs to
154  // be done instead of making a special case here?
155 
156  // Special case: FailInputFile incident must set the application return code
157  if ( incident.type() == IncidentType::FailInputFile || incident.type() == IncidentType::CorruptedInputFile ) {
158  auto appmgr = serviceLocator()->as<IProperty>();
159  Gaudi::setAppReturnCode( appmgr, incident.type() == IncidentType::FailInputFile
162  .ignore();
163  }
164 
165  auto ilisteners = m_listenerMap.find( listenerType );
166  if ( m_listenerMap.end() == ilisteners ) return;
167 
168  // setting this pointer will avoid that a call to removeListener() during
169  // the loop triggers a segfault
170  m_currentIncidentType = &incident.type();
171  std::string curIncTyp;
172  if ( m_currentIncidentType != nullptr ) {
173  curIncTyp = *m_currentIncidentType;
174  } else {
175  curIncTyp = "UNKNOWN";
176  }
177 
178  bool firedSingleShot = false;
179 
180  auto& listeners = *ilisteners->second;
181 
182  for ( auto& listener : listeners ) {
183 
184  VERMSG << "Calling '" << getListenerName( listener.iListener ) << "' for incident [" << incident.type() << "]"
185  << endmsg;
186 
187  // handle exceptions if they occur
188  try {
189  listener.iListener->handle( incident );
190  } catch ( const GaudiException& exc ) {
191  error() << "Exception with tag=" << exc.tag()
192  << " is caught"
193  " handling incident "
194  << curIncTyp << " in listener " << getListenerName( listener.iListener ) << endmsg;
195  error() << exc << endmsg;
196  if ( listener.rethrow ) { throw exc; }
197  } catch ( const std::exception& exc ) {
198  error() << "Standard std::exception is caught"
199  " handling incident "
200  << curIncTyp << " in listener " << getListenerName( listener.iListener ) << endmsg;
201  error() << exc.what() << endmsg;
202  if ( listener.rethrow ) { throw exc; }
203  } catch ( ... ) {
204  error() << "UNKNOWN Exception is caught"
205  " handling incident "
206  << curIncTyp << " in listener " << getListenerName( listener.iListener ) << endmsg;
207  if ( listener.rethrow ) { throw; }
208  }
209  // check wheter one of the listeners is singleShot
210  firedSingleShot |= listener.singleShot;
211  }
212  if ( firedSingleShot ) {
213  // remove all the singleshot listeners that got their shot...
214  listeners.erase( std::remove_if( std::begin( listeners ), std::end( listeners ), isSingleShot ),
215  std::end( listeners ) );
216  if ( listeners.empty() ) m_listenerMap.erase( ilisteners );
217  }
218 
219  m_currentIncidentType = nullptr;
220 }
221 // ============================================================================
222 void IncidentSvc::fireIncident( const Incident& incident ) {
223 
225 
226  // Call specific listeners
227  i_fireIncident( incident, incident.type() );
228  // Try listeners registered for ALL incidents
229  if ( incident.type() != "ALL" ) { // avoid double calls if somebody fires the incident "ALL"
230  i_fireIncident( incident, "ALL" );
231  }
232 }
233 // ============================================================================
235 
236  const EventContext& ctx = incident->context();
237  DEBMSG << "Async incident '" << incident->type() << "' fired on context " << ctx << endmsg;
238 
239  // create or get incident queue for slot
240  auto [incItr, inserted1] = m_firedIncidents.insert( {ctx.slot(), IncQueue_t()} );
241  // save or get current event for slot
242  auto [slotItr, inserted2] = m_slotEvent.insert( {ctx.slot(), ctx.evt()} );
243 
244  // if new event in slot, clear all remaining old incidents
245  if ( slotItr->second != ctx.evt() ) {
246  slotItr->second = ctx.evt();
247 
248  if ( msgLevel( MSG::DEBUG ) and !incItr->second.empty() ) {
249  debug() << "Clearing remaining obsolete incidents from slot " << ctx.slot() << ":";
250  Incident* inc( nullptr );
251  while ( incItr->second.try_pop( inc ) ) { debug() << " " << inc->type() << "(" << inc->context() << ")"; }
252  debug() << endmsg;
253  }
254  incItr->second.clear();
255  }
256  incItr->second.push( incident.release() );
257 }
258 // ============================================================================
259 
261  static const std::string ALL{"ALL"};
262  auto lock = std::scoped_lock{m_listenerMapMutex};
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 
279  if ( ctx ) {
280  auto incs = m_firedIncidents.find( ctx->slot() );
281  if ( incs != m_firedIncidents.end() ) {
282  Incident* inc( nullptr );
283 
284  DEBMSG << "Collecting listeners fired on context " << *ctx << endmsg;
285  while ( incs->second.try_pop( inc ) ) {
286  // ensure incident is for this event (should not be necessary)
287  if ( inc->context().evt() == ctx->evt() ) {
288  std::scoped_lock lock( m_listenerMapMutex );
289  auto i = m_listenerMap.find( inc->type() );
290  if ( i != m_listenerMap.end() ) {
291  p.emplace_back( std::move( inc ), std::vector<Listener>{i->second->begin(), i->second->end()} );
292  }
293  }
294  }
295  }
296  }
297  return p;
298 }
299 // ============================================================================
300 // The END
301 // ============================================================================
AlgSequencer.all
all
Definition: AlgSequencer.py:54
MSG::DEBUG
@ DEBUG
Definition: IMessageSvc.h:25
DEBMSG
#define DEBMSG
Definition: IncidentSvc.cpp:53
IIncidentSvc::Listener
Listener properties.
Definition: IIncidentSvc.h:60
System::milliSec
@ milliSec
Definition: Timing.h:67
std::for_each
T for_each(T... args)
IncidentSvc::~IncidentSvc
~IncidentSvc() override
Definition: IncidentSvc.cpp:61
ON_DEBUG
#define ON_DEBUG
Definition: IncidentSvc.cpp:50
std::string
STL class.
std::exception
STL class.
AppReturnCode.h
std::move
T move(T... args)
GaudiUtils::Map::find
iterator find(const key_type &key)
Definition: Map.h:157
GaudiException.h
std::vector
STL class.
ISvcLocator
Definition: ISvcLocator.h:46
std::back_inserter
T back_inserter(T... args)
GaudiException
Definition: GaudiException.h:31
VERMSG
#define VERMSG
Definition: IncidentSvc.cpp:54
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:148
std::unique_ptr::release
T release(T... args)
IncidentSvc::m_firedIncidents
tbb::concurrent_unordered_map< EventContext::ContextID_t, IncQueue_t > m_firedIncidents
Definition: IncidentSvc.h:100
GaudiKernel.Constants.ALL
int ALL
Definition: Constants.py:21
gaudirun.c
c
Definition: gaudirun.py:499
IncidentSvc::m_timerLock
bool m_timerLock
Definition: IncidentSvc.h:95
LockedChrono.h
CommonMessaging< implements< IService, IProperty, IStateful > >::msgLevel
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
Definition: CommonMessaging.h:148
Service::finalize
StatusCode finalize() override
Definition: Service.cpp:222
Gaudi::ReturnCode::FailInput
constexpr int FailInput
Definition: AppReturnCode.h:33
IncidentSvc::m_timer
ChronoEntity m_timer
timer & it's lock
Definition: IncidentSvc.h:94
IncidentSvc
Default implementation of the IIncidentSvc interface.
Definition: IncidentSvc.h:48
IProperty
Definition: IProperty.h:33
IIncidentListener
Definition: IIncidentListener.h:25
SmartIF.h
Incident::context
EventContext context() const
Access to the EventContext of the source of the incident.
Definition: Incident.h:60
TimingHistograms.name
name
Definition: TimingHistograms.py:23
GaudiPython.Pythonizations.ctx
ctx
Definition: Pythonizations.py:566
StatusCode
Definition: StatusCode.h:65
Gaudi::setAppReturnCode
StatusCode setAppReturnCode(SmartIF< IProperty > &appmgr, int value, bool force=false)
Set the application return code.
Definition: AppReturnCode.h:59
IncidentSvc::addListener
void addListener(IIncidentListener *lis, const std::string &type="", long priority=0, bool rethrow=false, bool singleShot=false) override
Definition: IncidentSvc.cpp:82
ChronoEntity::outputUserTime
std::string outputUserTime() const
print the chrono ;
Definition: ChronoEntity.cpp:82
CommonMessaging
Definition: CommonMessaging.h:66
Gaudi::Utils::LockedChrono
Definition: LockedChrono.h:60
Gaudi::ReturnCode::CorruptedInput
constexpr int CorruptedInput
Definition: AppReturnCode.h:38
IncidentSvc::removeListenerFromList
ListenerMap::iterator removeListenerFromList(ListenerMap::iterator, IIncidentListener *item, bool scheduleRemoval)
Definition: IncidentSvc.cpp:110
SmartIF< INamedInterface >
MsgStream::clear
void clear(STATE_TYPE _i=std::ios_base::failbit)
Definition: MsgStream.h:181
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:202
GaudiException::tag
virtual const std::string & tag() const
name tag for the exception, or exception type
Definition: GaudiException.h:77
std::remove_if
T remove_if(T... args)
IncidentSvc::m_slotEvent
tbb::concurrent_unordered_map< EventContext::ContextID_t, EventContext::ContextEvt_t > m_slotEvent
Event ID for each slot.
Definition: IncidentSvc.h:103
std::transform
T transform(T... args)
GaudiUtils::Map::end
iterator end()
Definition: Map.h:140
GaudiUtils::Map::erase
iterator erase(const_iterator pos)
Definition: Map.h:192
StatusCode::ignore
const StatusCode & ignore() const
Allow discarding a StatusCode without warning.
Definition: StatusCode.h:156
SmartIF::as
SmartIF< IFace > as() const
return a new SmartIF instance to another interface
Definition: SmartIF.h:117
IncidentSvc::fireIncident
void fireIncident(const Incident &incident) override
Definition: IncidentSvc.cpp:222
gaudirun.type
type
Definition: gaudirun.py:154
std::vector::emplace_back
T emplace_back(T... args)
System::Sec
@ Sec
Definition: Timing.h:67
gaudirun.l
dictionary l
Definition: gaudirun.py:543
std::begin
T begin(T... args)
IncidentSvc.h
IIncidentListener.h
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:46
IncidentSvc::m_listenerMapMutex
std::recursive_mutex m_listenerMapMutex
Mutex to synchronize access to m_listenerMap.
Definition: IncidentSvc.h:91
GaudiUtils::Map< Gaudi::StringKey, std::unique_ptr< ListenerList >, std::unordered_map< Gaudi::StringKey, std::unique_ptr< ListenerList >, Hash< Gaudi::StringKey > > >::iterator
map_type::iterator iterator
Definition: Map.h:107
EventContext
Definition: EventContext.h:34
GaudiUtils::Map::insert
std::pair< iterator, bool > insert(ValueType &&val)
Definition: Map.h:178
IncidentSvc::removeListener
void removeListener(IIncidentListener *l, const std::string &type="") override
Definition: IncidentSvc.cpp:128
Incident::type
const std::string & type() const
Access to the incident type.
Definition: Incident.h:48
IncidentSvc::IncidentSvc
IncidentSvc(const std::string &name, ISvcLocator *svc)
Definition: IncidentSvc.cpp:59
std::end
T end(T... args)
std::partition_point
T partition_point(T... args)
ISvcLocator.h
Incident.h
IncidentSvc::m_currentIncidentType
const std::string * m_currentIncidentType
Incident being fired.
Definition: IncidentSvc.h:88
Incident
Definition: Incident.h:27
std::unique_ptr
STL class.
IncidentSvc::getIncidents
IIncidentSvc::IncidentPack getIncidents(const EventContext *ctx) override
Definition: IncidentSvc.cpp:277
IncidentSvc::getListeners
void getListeners(std::vector< IIncidentListener * > &lis, const std::string &type="") const override
Definition: IncidentSvc.cpp:260
IncidentSvc::IncQueue_t
tbb::concurrent_queue< Incident * > IncQueue_t
Definition: IncidentSvc.h:99
EventContext::evt
ContextEvt_t evt() const
Definition: EventContext.h:50
std::exception::what
T what(T... args)
IncidentSvc::m_listenerMap
ListenerMap m_listenerMap
List of auditor names.
Definition: IncidentSvc.h:84
MsgStream.h
Service::serviceLocator
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator
Definition: Service.cpp:335
std::next
T next(T... args)
IncidentSvc::finalize
StatusCode finalize() override
Definition: IncidentSvc.cpp:63