The Gaudi Framework  v30r3 (a5ef0a68)
ServiceManager.cpp
Go to the documentation of this file.
1 // Include files
2 #include "ServiceManager.h"
5 #include "GaudiKernel/IService.h"
6 #include "GaudiKernel/Incident.h"
9 #include "GaudiKernel/Service.h"
10 #include "GaudiKernel/SmartIF.h"
11 #include "GaudiKernel/System.h"
13 #include "GaudiKernel/reverse.h"
14 
15 #include <algorithm>
16 #include <cassert>
17 #include <functional>
18 #include <iostream>
19 
20 #define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
21 #define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
22 
23 #define DEBMSG ON_DEBUG debug()
24 #define VERMSG ON_VERBOSE verbose()
25 
27 static SmartIF<IService> no_service;
28 
30 namespace
31 {
32  template <typename C>
33  std::vector<IService*> activeSvc( const C& lst )
34  {
36  v.reserve( lst.size() );
37  for ( auto& i : lst ) {
38  if ( i.active ) v.push_back( i.service.get() );
39  }
40  return v;
41  }
42 }
43 
44 // constructor
46  : base_class( application, IService::interfaceID() ), m_appSvc( application )
47 {
48  // Set the service locator to myself
49  m_svcLocator = this;
50  addRef(); // increase ref count, so we live forever...
51 }
52 
53 // destructor
55 {
56  //-- inform the orphan services that I am gone....
57  for ( auto& svc : m_listsvc ) svc.service->setServiceManager( nullptr );
58 }
59 
60 //------------------------------------------------------------------------------
61 // Instantiate a service
63 //------------------------------------------------------------------------------
64 {
65  // Check if the service is already existing
66  if ( existsService( typeName.name() ) ) {
67  // return an error because a service with that name already exists
68  return no_service;
69  }
70 
71  const std::string& name = typeName.name();
72  std::string type = typeName.type();
73  if ( !typeName.haveType() ) { // the type is not explicit
74  // see we have some specific type mapping for the name
75  auto it = m_maptype.find( typeName.name() );
76  if ( it != m_maptype.end() ) {
77  type = it->second; // use the declared type
78  }
79  }
80 
82  auto ip = type.find( "__" );
83  if ( ip != std::string::npos ) type.erase( ip, type.length() );
84 
85  IService* service = Service::Factory::create( type, name, this ).release();
86  if ( !service ) {
87  fatal() << "No Service factory for " << type << " available." << endmsg;
88  return no_service;
89  }
90  // Check the compatibility of the version of the interface obtained
91  if ( !isValidInterface( service ) ) {
92  fatal() << "Incompatible interface IService version for " << type << endmsg;
93  return no_service;
94  }
95 
96  m_listsvc.push_back( service );
97  service->setServiceManager( this );
98  return m_listsvc.back().service; // DANGER: returns a reference to a SmartIF in m_listsvc, and hence does no longer
99  // allow relocations of those...
100 }
101 
102 //------------------------------------------------------------------------------
103 // add a service to the managed list
105 //------------------------------------------------------------------------------
106 {
107  ListSvc::iterator it = find( svc );
108  LockGuard_t lck( m_gLock );
109  if ( it != m_listsvc.end() ) {
110  it->priority = prio; // if the service is already known, it is equivalent to a setPriority
111  it->active = true; // and make it active
112  } else {
113  m_listsvc.emplace_back( svc, prio, true );
114  }
115  return StatusCode::SUCCESS;
116 }
117 
118 //------------------------------------------------------------------------------
119 // add the service with the give type and name to the active list
121 //------------------------------------------------------------------------------
122 {
123  auto it = find( typeName.name() ); // try to find the service by name
124  if ( it == m_listsvc.end() ) { // not found
125  // If the service does not exist, we create it
126  SmartIF<IService>& svc =
127  createService( typeName ); // WARNING: svc is now a reference to something that lives in m_listsvc
128  if ( !svc ) return StatusCode::FAILURE;
129  it = find( svc.get() ); // now it is in the list because createService added it
130  it->priority = prio;
132  if ( targetFSMState() >= Gaudi::StateMachine::INITIALIZED ) { // WARNING: this can trigger a recursion!!!
133  sc = svc->sysInitialize();
135  sc = svc->sysStart();
136  }
137  }
138  if ( sc.isFailure() ) { // if initialization failed, remove it from the list
139  error() << "Unable to initialize service \"" << typeName.name() << "\"" << endmsg;
140  LockGuard_t lck( m_gLock );
141  m_listsvc.erase( it );
142  // Note: removing it from the list + the SmartIF going out of scope should trigger the delete
143  // delete svc.get();
144  return sc;
145  }
146  // initialization successful, we can work with the service
147  // Move the just initialized service to the back of the list
148  // (we care more about order of initialization than of creation)
149  LockGuard_t lck( m_gLock );
150  m_listsvc.push_back( *it );
151  m_listsvc.erase( it );
152  it = std::prev( std::end( m_listsvc ) ); // last entry (the iterator was invalidated by erase)
153  } else {
154  // if the service is already known, it is equivalent to a setPriority
155  it->priority = prio;
156  }
157  // 'it' is defined because either we found the service or we created it
158  // Now we can activate the service
159  it->active = true; // and make it active
160  return StatusCode( StatusCode::SUCCESS, true );
161 }
162 
163 //------------------------------------------------------------------------------
164 // Returns a smart pointer to a service.
166 {
167  const std::string& name = typeName.name();
168 
169  // Acquire the RAII lock to avoid simultaneous attempts from different threads to initialize a service
170 
171  Mutex_t* imut;
172  {
173  // get the global lock, then extract/create the service specific mutex
174  // then release global lock
175 
176  LockGuard_t lk( m_gLock );
177  auto mit = m_lockMap.find( name );
178  if ( mit == m_lockMap.end() ) {
180  .first;
181  }
182  imut = &mit->second;
183  }
184 
185  {
186  // now we have the service specific lock on the above mutex
187  LockGuard_t lk2( *imut );
188 
189  auto it = find( name );
190 
191  if ( it != m_listsvc.end() ) {
192  if ( m_loopCheck && ( createIf && it->service->FSMState() == Gaudi::StateMachine::CONFIGURED ) ) {
193  error() << "Initialization loop detected when creating service \"" << name << "\"" << endmsg;
194  return no_service;
195  }
196  return it->service;
197  }
198 
199  // Service not found. The user may be interested in one of the interfaces
200  // of the application manager itself
201  if ( name == "ApplicationMgr" || name == "APPMGR" || name == "" ) {
202  return m_appSvc;
203  }
204 
205  // last resort: we try to create the service
206  if ( createIf && addService( typeName ).isSuccess() ) {
207  return find( name )->service;
208  }
209 
210  return no_service;
211  }
212 }
213 
214 //------------------------------------------------------------------------------
216 //------------------------------------------------------------------------------
217 {
220  []( ListSvc::const_reference i ) { return const_cast<IService*>( i.service.get() ); } );
221  return m_listOfPtrs;
222 }
223 
224 //------------------------------------------------------------------------------
226 //------------------------------------------------------------------------------
227 {
228  return find( name ) != m_listsvc.end();
229 }
230 
231 //------------------------------------------------------------------------------
233 //------------------------------------------------------------------------------
234 {
235  auto it = find( svc );
236  if ( it == m_listsvc.end() ) return StatusCode( StatusCode::FAILURE, true );
237  m_listsvc.erase( it );
238  return StatusCode( StatusCode::SUCCESS, true );
239 }
240 
241 //------------------------------------------------------------------------------
243 //------------------------------------------------------------------------------
244 {
245  auto it = find( name );
246  if ( it == m_listsvc.end() ) return StatusCode::FAILURE;
247  m_listsvc.erase( it );
248  return StatusCode::SUCCESS;
249 }
250 
251 //------------------------------------------------------------------------------
253 //------------------------------------------------------------------------------
254 {
255  // once we get to C++17, replace with m_maptype.insert_or_assign...
256  auto p = m_maptype.emplace( svcname, svctype );
257  if ( !p.second ) p.first->second = svctype;
258  return StatusCode::SUCCESS;
259 }
260 
261 //------------------------------------------------------------------------------
263 //------------------------------------------------------------------------------
264 {
265  // ensure that the list is ordered by priority
266  m_listsvc.sort();
267  // we work on a copy to avoid to operate twice on the services created on demand
268  // which are already in the correct state.
269 
270  StatusCode sc( StatusCode::SUCCESS, true );
271  // call initialize() for all services
272  for ( auto& it : activeSvc( m_listsvc ) ) {
273  const std::string& name = it->name();
274  switch ( it->FSMState() ) {
276  DEBMSG << "Service " << name << " already initialized" << endmsg;
277  break;
279  DEBMSG << "Initializing service " << name << endmsg;
280  sc = it->sysInitialize();
281  if ( !sc.isSuccess() ) {
282  error() << "Unable to initialize Service: " << name << endmsg;
283  return sc;
284  }
285  break;
286  default:
287  error() << "Service " << name << " not in the correct state to be initialized (" << it->FSMState() << ")"
288  << endmsg;
289  return StatusCode::FAILURE;
290  }
291  }
292  return StatusCode::SUCCESS;
293 }
294 
295 //------------------------------------------------------------------------------
297 //------------------------------------------------------------------------------
298 {
299  // ensure that the list is ordered by priority
300  m_listsvc.sort();
301  // we work on a copy to avoid to operate twice on the services created on demand
302  // (which are already in the correct state.
303  // only act on active services
304  StatusCode sc( StatusCode::SUCCESS, true );
305  // call initialize() for all services
306  for ( auto& it : activeSvc( m_listsvc ) ) {
307  const std::string& name = it->name();
308  switch ( it->FSMState() ) {
310  DEBMSG << "Service " << name << " already started" << endmsg;
311  break;
313  DEBMSG << "Starting service " << name << endmsg;
314  sc = it->sysStart();
315  if ( !sc.isSuccess() ) {
316  error() << "Unable to start Service: " << name << endmsg;
317  return sc;
318  }
319  break;
320  default:
321  error() << "Service " << name << " not in the correct state to be started (" << it->FSMState() << ")" << endmsg;
322  return StatusCode::FAILURE;
323  }
324  }
325  return StatusCode::SUCCESS;
326 }
327 
328 //------------------------------------------------------------------------------
330 //------------------------------------------------------------------------------
331 {
332  // ensure that the list is ordered by priority
333  m_listsvc.sort();
334  // we work on a copy to avoid to operate twice on the services created on demand
335  // which are already in the correct state.
336  // only act on active services
337 
338  StatusCode sc( StatusCode::SUCCESS, true );
339  // call stop() for all services
340  for ( const auto& svc : reverse( activeSvc( m_listsvc ) ) ) {
341  const std::string& name = svc->name();
342  switch ( svc->FSMState() ) {
344  DEBMSG << "Service " << name << " already stopped" << endmsg;
345  break;
347  DEBMSG << "Stopping service " << name << endmsg;
348  sc = svc->sysStop();
349  if ( !sc.isSuccess() ) {
350  error() << "Unable to stop Service: " << name << endmsg;
351  return sc;
352  }
353  break;
354  default:
355  DEBMSG << "Service " << name << " not in the correct state to be stopped (" << svc->FSMState() << ")" << endmsg;
356  return StatusCode::FAILURE;
357  }
358  }
359  return StatusCode::SUCCESS;
360 }
361 
362 //------------------------------------------------------------------------------
364 //------------------------------------------------------------------------------
365 {
366  // ensure that the list is ordered by priority
367  m_listsvc.sort();
368  // we work on a copy to avoid to operate twice on the services created on demand
369  // which are already in the correct state.
370  // only act on active services
371  StatusCode sc( StatusCode::SUCCESS, true );
372  // Re-Initialize all services
373  for ( auto& svc : activeSvc( m_listsvc ) ) {
374  sc = svc->sysReinitialize();
375  if ( !sc.isSuccess() ) {
376  error() << "Unable to re-initialize Service: " << svc->name() << endmsg;
377  return StatusCode::FAILURE;
378  }
379  }
380  return StatusCode::SUCCESS;
381 }
382 
383 //------------------------------------------------------------------------------
385 //------------------------------------------------------------------------------
386 {
387  // ensure that the list is ordered by priority
388  m_listsvc.sort();
389  // we work on a copy to avoid to operate twice on the services created on demand
390  // which are already in the correct state.
391  // only act on active services
392  StatusCode sc( StatusCode::SUCCESS, true );
393  // Re-Start all services
394  for ( auto& svc : activeSvc( m_listsvc ) ) {
395  sc = svc->sysRestart();
396  if ( !sc.isSuccess() ) {
397  error() << "Unable to re-start Service: " << svc->name() << endmsg;
398  return StatusCode::FAILURE;
399  }
400  }
401  return StatusCode::SUCCESS;
402 }
403 
404 //------------------------------------------------------------------------------
406 //------------------------------------------------------------------------------
407 {
408  // make sure that HistogramDataSvc and THistSvc get finalized after the
409  // ToolSvc, and the FileMgr and StatusCodeSvc after that
410  int pri_tool = getPriority( "ToolSvc" );
411  if ( pri_tool != 0 ) {
412  setPriority( "THistSvc", pri_tool - 10 ).ignore();
413  setPriority( "ChronoStatSvc", pri_tool - 20 ).ignore();
414  setPriority( "AuditorSvc", pri_tool - 30 ).ignore();
415  setPriority( "NTupleSvc", pri_tool - 10 ).ignore();
416  setPriority( "HistogramDataSvc", pri_tool - 10 ).ignore();
417  // Preserve the relative ordering between HistogramDataSvc and HistogramPersistencySvc
418  setPriority( "HistogramPersistencySvc", pri_tool - 20 ).ignore();
419  setPriority( "HistorySvc", pri_tool - 30 ).ignore();
420  setPriority( "FileMgr", pri_tool - 40 ).ignore();
421  }
422 
423  // get list of PostFinalize clients
425  auto p_inc = service<IIncidentSvc>( "IncidentSvc", false );
426  if ( p_inc ) {
427  p_inc->getListeners( postFinList, IncidentType::SvcPostFinalize );
428  p_inc.reset();
429  }
430 
431  // make sure the StatusCodeSvc gets finalized really late:
432  setPriority( "StatusCodeSvc", -9999 ).ignore();
433 
434  // ensure that the list is ordered by priority
435  m_listsvc.sort();
436  // dump();
437 
438  StatusCode sc( StatusCode::SUCCESS, true );
439  {
440  // we work on a copy to avoid to operate twice on the services created on demand
441  // which are already in the correct state.
442  // only act on active services
443  // call finalize() for all services in reverse order
444  for ( const auto& svc : reverse( activeSvc( m_listsvc ) ) ) {
445  const std::string& name = svc->name();
446  // ignore the current state for the moment
447  // if( Gaudi::StateMachine::INITIALIZED == svc->state() )
448  DEBMSG << "Finalizing service " << name << endmsg;
449  if ( !svc->sysFinalize().isSuccess() ) {
450  warning() << "Finalization of service " << name << " failed" << endmsg;
451  sc = StatusCode::FAILURE;
452  }
453  }
454  }
455 
456  // call SvcPostFinalize on all clients
457  if ( !postFinList.empty() ) {
458  DEBMSG << "Will call SvcPostFinalize for " << postFinList.size() << " clients" << endmsg;
459  Incident inc( "ServiceManager", IncidentType::SvcPostFinalize );
460  for ( auto& itr : postFinList ) itr->handle( inc );
461  }
462 
463  // loop over all Active Services, removing them one by one.
464  // They should be deleted because the reference counting goes to 0.
465  DEBMSG << "Looping over all active services..." << endmsg;
466  auto it = m_listsvc.begin();
467  while ( it != m_listsvc.end() ) {
468  DEBMSG << "---- " << it->service->name() << " (refCount = " << it->service->refCount() << ")" << endmsg;
469  if ( it->service->refCount() < 1 ) {
470  warning() << "Too low reference count for " << it->service->name() << " (should not go below 1 at this point)"
471  << endmsg;
472  it->service->addRef();
473  }
474  if ( it->active ) {
475  it = m_listsvc.erase( it );
476  } else {
477  ++it;
478  }
479  }
480  return sc;
481 }
482 
483 //------------------------------------------------------------------------------
485 {
486  //------------------------------------------------------------------------------
487  auto it = find( name );
488  return ( it != m_listsvc.end() ) ? it->priority : 0;
489 }
490 
491 //------------------------------------------------------------------------------
493 {
494  //------------------------------------------------------------------------------
495  auto it = find( name );
496  if ( it == m_listsvc.end() ) return StatusCode::FAILURE;
497  it->priority = prio;
498  return StatusCode::SUCCESS;
499 }
500 
501 //------------------------------------------------------------------------------
502 // Get the value of the initialization loop check flag.
503 //------------------------------------------------------------------------------
505 //------------------------------------------------------------------------------
506 // Set the value of the initialization loop check flag.
507 //------------------------------------------------------------------------------
509 
510 //------------------------------------------------------------------------------
511 // Dump out contents of service list
512 //------------------------------------------------------------------------------
514 {
515 
516  auto& log = info();
517  log << "\n"
518  << "===================== listing all services ===================\n"
519  << " prior ref name active\n";
520 
521  for ( const auto& svc : m_listsvc ) {
522 
523  log.width( 6 );
524  log.flags( std::ios_base::right );
525  log << svc.priority << " ";
526  log.width( 5 );
527  log << svc.service->refCount() << " ";
528  log.width( 30 );
529  log.flags( std::ios_base::left );
530  log << svc.service->name() << " ";
531  log.width( 2 );
532  log << svc.active << std::endl;
533  }
534 
535  log << "=================================================================\n";
536  log << endmsg;
537 }
538 
540 {
541  resetMessaging();
542  for ( auto& svcItem : m_listsvc ) {
543  const auto svc = dynamic_cast<Service*>( svcItem.service.get() );
544  if ( svc ) svc->resetMessaging();
545  }
546 }
547 
The ServiceManager class is in charge of the creation of concrete instances of Services.
std::list< IService * > m_listOfPtrs
List of pointers to the know services used to implement getServices()
constexpr static const auto FAILURE
Definition: StatusCode.h:88
void setLoopCheckEnabled(bool en) override
Set the value of the initialization loop check flag.
SmartIF< IService > m_appSvc
Pointer to the application IService interface.
T empty(T...args)
boost::lock_guard< Mutex_t > LockGuard_t
T forward_as_tuple(T...args)
StatusCode finalize() override
Finalize (from INITIALIZED to CONFIGURED).
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
MSG::Level resetMessaging()
Reinitialize internal states.
bool isSuccess() const
Definition: StatusCode.h:287
SmartIF< ISvcLocator > m_svcLocator
Service locator (needed to access the MessageSvc)
bool m_loopCheck
Check for service initialization loops.
ServiceManager(IInterface *application)
default creator
T endl(T...args)
Gaudi::StateMachine::State targetFSMState() const override
When we are in the middle of a transition, get the state where the transition is leading us...
boost::recursive_mutex Mutex_t
Mutex to synchronize shared service initialization between threads.
StatusCode restart() override
Initialization (from RUNNING to RUNNING, via INITIALIZED).
T end(T...args)
bool isValidInterface(I *i)
Templated function that throws an exception if the version if the interface implemented by the object...
Definition: IInterface.h:378
bool isFailure() const
Definition: StatusCode.h:139
MapType m_maptype
Map of service name and service type.
T prev(T...args)
STL class.
TYPE * get() const
Get interface pointer.
Definition: SmartIF.h:82
virtual StatusCode sysInitialize()=0
Initialize Service.
T push_back(T...args)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
bool existsService(const std::string &name) const override
implementation of ISvcLocation::existsService
StatusCode stop() override
Stop (from RUNNING to INITIALIZED).
iterator end()
Definition: Map.h:134
Helper class to parse a string of format "type/name".
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
bool loopCheckEnabled() const override
Get the value of the initialization loop check flag.
void dump() const
General service interface definition.
Definition: IService.h:18
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:51
Definition of the basic interface.
Definition: IInterface.h:277
~ServiceManager() override
virtual destructor
#define DECLARE_OBJECT_FACTORY(x)
Definition: ObjectFactory.h:15
T erase(T...args)
const std::string & name() const override
Return the name of the manager (implementation of INamedInterface)
iterator find(const key_type &key)
Definition: Map.h:151
const std::list< IService * > & getServices() const override
Return the list of Services.
StatusCode start() override
Start (from INITIALIZED to RUNNING).
std::pair< iterator, bool > emplace(Args &&...args)
Definition: Map.h:169
T clear(T...args)
details::reverse_wrapper< T > reverse(T &&iterable)
Definition: reverse.h:52
constexpr static const auto SUCCESS
Definition: StatusCode.h:87
int getPriority(const std::string &name) const override
manage priorities of services
T find(T...args)
T length(T...args)
void outputLevelUpdate() override
Function to call to update the outputLevel of the components (after a change in MessageSvc).
STL class.
virtual StatusCode sysStart()=0
Start Service.
T begin(T...args)
T back_inserter(T...args)
const std::string & type() const
const StatusCode & ignore() const
Ignore/check StatusCode.
Definition: StatusCode.h:165
StatusCode reinitialize() override
Initialization (from INITIALIZED or RUNNING to INITIALIZED, via CONFIGURED).
Base class for all Incidents (computing events).
Definition: Incident.h:17
T emplace(T...args)
T back(T...args)
ListSvc::iterator find(const std::string &name)
StatusCode declareSvcType(const std::string &svcname, const std::string &svctype) override
implementation of ISvcManager::declareSvcType
T sort(T...args)
T transform(T...args)
#define DEBMSG
const std::string & name() const
StatusCode setPriority(const std::string &name, int pri) override
StatusCode removeService(IService *svc) override
implementation of ISvcManager::removeService
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
SmartIF< IService > & service(const Gaudi::Utils::TypeNameString &typeName, const bool createIf=true) override
Returns a smart pointer to a service.
std::string typeName(const std::type_info &typ)
Definition: Dictionary.cpp:23
ListSvc m_listsvc
List of service maintained by ServiceManager This contains SmartIF<T> for all services – and because...
Base class for all services.
Definition: Service.h:36
virtual void setServiceManager(ISvcManager *)=0
SmartIF< IService > & createService(const Gaudi::Utils::TypeNameString &nametype) override
implementation of ISvcManager::createService NOTE: as this returns a &, we must guarantee that once c...
SmartIF< IService > service
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:209
std::map< std::string, Mutex_t > m_lockMap
T reserve(T...args)
StatusCode addService(IService *svc, int prio=DEFAULT_SVC_PRIORITY) override
implementation of ISvcManager::addService
T emplace_back(T...args)
StatusCode initialize() override
Initialization (from CONFIGURED to INITIALIZED).