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