Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v31r0 (aeb156f0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  template <typename C>
32  std::vector<IService*> activeSvc( const C& lst ) {
34  v.reserve( lst.size() );
35  for ( auto& i : lst ) {
36  if ( i.active ) v.push_back( i.service.get() );
37  }
38  return v;
39  }
40 } // namespace
41 
42 // constructor
44  : base_class( application, IService::interfaceID() ), m_appSvc( application ) {
45  // Set the service locator to myself
46  m_svcLocator = this;
47  addRef(); // increase ref count, so we live forever...
48 }
49 
50 // destructor
52  //-- inform the orphan services that I am gone....
53  for ( auto& svc : m_listsvc ) svc.service->setServiceManager( nullptr );
54 }
55 
56 //------------------------------------------------------------------------------
57 // Instantiate a service
59 //------------------------------------------------------------------------------
60 {
61  // Check if the service is already existing
62  if ( existsService( typeName.name() ) ) {
63  // return an error because a service with that name already exists
64  return no_service;
65  }
66 
67  const std::string& name = typeName.name();
68  std::string type = typeName.type();
69  if ( !typeName.haveType() ) { // the type is not explicit
70  // see we have some specific type mapping for the name
71  auto it = m_maptype.find( typeName.name() );
72  if ( it != m_maptype.end() ) {
73  type = it->second; // use the declared type
74  }
75  }
76 
78  auto ip = type.find( "__" );
79  if ( ip != std::string::npos ) type.erase( ip, type.length() );
80 
81  IService* service = Service::Factory::create( type, name, this ).release();
82  if ( !service ) {
83  fatal() << "No Service factory for " << type << " available." << endmsg;
84  return no_service;
85  }
86  // Check the compatibility of the version of the interface obtained
87  if ( !isValidInterface( service ) ) {
88  fatal() << "Incompatible interface IService version for " << type << endmsg;
89  return no_service;
90  }
91 
92  m_listsvc.push_back( service );
93  service->setServiceManager( this );
94  return m_listsvc.back().service; // DANGER: returns a reference to a SmartIF in m_listsvc, and hence does no longer
95  // allow relocations of those...
96 }
97 
98 //------------------------------------------------------------------------------
99 // add a service to the managed list
101 //------------------------------------------------------------------------------
102 {
103  ListSvc::iterator it = find( svc );
104  LockGuard_t lck( m_gLock );
105  if ( it != m_listsvc.end() ) {
106  it->priority = prio; // if the service is already known, it is equivalent to a setPriority
107  it->active = true; // and make it active
108  } else {
109  m_listsvc.emplace_back( svc, prio, true );
110  }
111  return StatusCode::SUCCESS;
112 }
113 
114 //------------------------------------------------------------------------------
115 // add the service with the give type and name to the active list
117 //------------------------------------------------------------------------------
118 {
119  auto it = find( typeName.name() ); // try to find the service by name
120  if ( it == m_listsvc.end() ) { // not found
121  // If the service does not exist, we create it
122  SmartIF<IService>& svc =
123  createService( typeName ); // WARNING: svc is now a reference to something that lives in m_listsvc
124  if ( !svc ) return StatusCode::FAILURE;
125  it = find( svc.get() ); // now it is in the list because createService added it
126  it->priority = prio;
128  if ( targetFSMState() >= Gaudi::StateMachine::INITIALIZED ) { // WARNING: this can trigger a recursion!!!
129  sc = svc->sysInitialize();
130  if ( sc.isSuccess() && targetFSMState() >= Gaudi::StateMachine::RUNNING ) { sc = svc->sysStart(); }
131  }
132  if ( sc.isFailure() ) { // if initialization failed, remove it from the list
133  error() << "Unable to initialize service \"" << typeName.name() << "\"" << endmsg;
134  LockGuard_t lck( m_gLock );
135  m_listsvc.erase( it );
136  // Note: removing it from the list + the SmartIF going out of scope should trigger the delete
137  // delete svc.get();
138  return sc;
139  }
140  // initialization successful, we can work with the service
141  // Move the just initialized service to the back of the list
142  // (we care more about order of initialization than of creation)
143  LockGuard_t lck( m_gLock );
144  m_listsvc.push_back( *it );
145  m_listsvc.erase( it );
146  it = std::prev( std::end( m_listsvc ) ); // last entry (the iterator was invalidated by erase)
147  } else {
148  // if the service is already known, it is equivalent to a setPriority
149  it->priority = prio;
150  }
151  // 'it' is defined because either we found the service or we created it
152  // Now we can activate the service
153  it->active = true; // and make it active
154  return StatusCode( StatusCode::SUCCESS, true );
155 }
156 
157 //------------------------------------------------------------------------------
158 // Returns a smart pointer to a service.
160  const std::string& name = typeName.name();
161 
162  // Acquire the RAII lock to avoid simultaneous attempts from different threads to initialize a service
163 
164  Mutex_t* imut;
165  {
166  // get the global lock, then extract/create the service specific mutex
167  // then release global lock
168 
169  LockGuard_t lk( m_gLock );
170  auto mit = m_lockMap.find( name );
171  if ( mit == m_lockMap.end() ) {
173  .first;
174  }
175  imut = &mit->second;
176  }
177 
178  {
179  // now we have the service specific lock on the above mutex
180  LockGuard_t lk2( *imut );
181 
182  auto it = find( name );
183 
184  if ( it != m_listsvc.end() ) {
185  if ( m_loopCheck && ( createIf && it->service->FSMState() == Gaudi::StateMachine::CONFIGURED ) ) {
186  error() << "Initialization loop detected when creating service \"" << name << "\"" << endmsg;
187  return no_service;
188  }
189  return it->service;
190  }
191 
192  // Service not found. The user may be interested in one of the interfaces
193  // of the application manager itself
194  if ( name == "ApplicationMgr" || name == "APPMGR" || name == "" ) { return m_appSvc; }
195 
196  // last resort: we try to create the service
197  if ( createIf && addService( typeName ).isSuccess() ) { return find( name )->service; }
198 
199  return no_service;
200  }
201 }
202 
203 //------------------------------------------------------------------------------
205 //------------------------------------------------------------------------------
206 {
209  []( ListSvc::const_reference i ) { return i.service.get(); } );
210  return m_listOfPtrs;
211 }
212 
213 //------------------------------------------------------------------------------
215 //------------------------------------------------------------------------------
216 {
217  return find( name ) != m_listsvc.end();
218 }
219 
220 //------------------------------------------------------------------------------
222 //------------------------------------------------------------------------------
223 {
224  auto it = find( svc );
225  if ( it == m_listsvc.end() ) return StatusCode( StatusCode::FAILURE, true );
226  m_listsvc.erase( it );
227  return StatusCode( StatusCode::SUCCESS, true );
228 }
229 
230 //------------------------------------------------------------------------------
232 //------------------------------------------------------------------------------
233 {
234  auto it = find( name );
235  if ( it == m_listsvc.end() ) return StatusCode::FAILURE;
236  m_listsvc.erase( it );
237  return StatusCode::SUCCESS;
238 }
239 
240 //------------------------------------------------------------------------------
242 //------------------------------------------------------------------------------
243 {
244  // once we get to C++17, replace with m_maptype.insert_or_assign...
245  auto p = m_maptype.emplace( svcname, svctype );
246  if ( !p.second ) p.first->second = svctype;
247  return StatusCode::SUCCESS;
248 }
249 
250 //------------------------------------------------------------------------------
252 //------------------------------------------------------------------------------
253 {
254  // ensure that the list is ordered by priority
255  m_listsvc.sort();
256  // we work on a copy to avoid to operate twice on the services created on demand
257  // which are already in the correct state.
258 
259  StatusCode sc( StatusCode::SUCCESS, true );
260  // call initialize() for all services
261  for ( auto& it : activeSvc( m_listsvc ) ) {
262  const std::string& name = it->name();
263  switch ( it->FSMState() ) {
265  DEBMSG << "Service " << name << " already initialized" << endmsg;
266  break;
268  DEBMSG << "Initializing service " << name << endmsg;
269  sc = it->sysInitialize();
270  if ( !sc.isSuccess() ) {
271  error() << "Unable to initialize Service: " << name << endmsg;
272  return sc;
273  }
274  break;
275  default:
276  error() << "Service " << name << " not in the correct state to be initialized (" << it->FSMState() << ")"
277  << endmsg;
278  return StatusCode::FAILURE;
279  }
280  }
281  return StatusCode::SUCCESS;
282 }
283 
284 //------------------------------------------------------------------------------
286 //------------------------------------------------------------------------------
287 {
288  // ensure that the list is ordered by priority
289  m_listsvc.sort();
290  // we work on a copy to avoid to operate twice on the services created on demand
291  // (which are already in the correct state.
292  // only act on active services
293  StatusCode sc( StatusCode::SUCCESS, true );
294  // call initialize() for all services
295  for ( auto& it : activeSvc( m_listsvc ) ) {
296  const std::string& name = it->name();
297  switch ( it->FSMState() ) {
299  DEBMSG << "Service " << name << " already started" << endmsg;
300  break;
302  DEBMSG << "Starting service " << name << endmsg;
303  sc = it->sysStart();
304  if ( !sc.isSuccess() ) {
305  error() << "Unable to start Service: " << name << endmsg;
306  return sc;
307  }
308  break;
309  default:
310  error() << "Service " << name << " not in the correct state to be started (" << it->FSMState() << ")" << endmsg;
311  return StatusCode::FAILURE;
312  }
313  }
314  return StatusCode::SUCCESS;
315 }
316 
317 //------------------------------------------------------------------------------
319 //------------------------------------------------------------------------------
320 {
321  // ensure that the list is ordered by priority
322  m_listsvc.sort();
323  // we work on a copy to avoid to operate twice on the services created on demand
324  // which are already in the correct state.
325  // only act on active services
326 
327  StatusCode sc( StatusCode::SUCCESS, true );
328  // call stop() for all services
329  for ( const auto& svc : reverse( activeSvc( m_listsvc ) ) ) {
330  const std::string& name = svc->name();
331  switch ( svc->FSMState() ) {
333  DEBMSG << "Service " << name << " already stopped" << endmsg;
334  break;
336  DEBMSG << "Stopping service " << name << endmsg;
337  sc = svc->sysStop();
338  if ( !sc.isSuccess() ) {
339  error() << "Unable to stop Service: " << name << endmsg;
340  return sc;
341  }
342  break;
343  default:
344  DEBMSG << "Service " << name << " not in the correct state to be stopped (" << svc->FSMState() << ")" << endmsg;
345  return StatusCode::FAILURE;
346  }
347  }
348  return StatusCode::SUCCESS;
349 }
350 
351 //------------------------------------------------------------------------------
353 //------------------------------------------------------------------------------
354 {
355  // ensure that the list is ordered by priority
356  m_listsvc.sort();
357  // we work on a copy to avoid to operate twice on the services created on demand
358  // which are already in the correct state.
359  // only act on active services
360  StatusCode sc( StatusCode::SUCCESS, true );
361  // Re-Initialize all services
362  for ( auto& svc : activeSvc( m_listsvc ) ) {
363  sc = svc->sysReinitialize();
364  if ( !sc.isSuccess() ) {
365  error() << "Unable to re-initialize Service: " << svc->name() << endmsg;
366  return StatusCode::FAILURE;
367  }
368  }
369  return StatusCode::SUCCESS;
370 }
371 
372 //------------------------------------------------------------------------------
374 //------------------------------------------------------------------------------
375 {
376  // ensure that the list is ordered by priority
377  m_listsvc.sort();
378  // we work on a copy to avoid to operate twice on the services created on demand
379  // which are already in the correct state.
380  // only act on active services
381  StatusCode sc( StatusCode::SUCCESS, true );
382  // Re-Start all services
383  for ( auto& svc : activeSvc( m_listsvc ) ) {
384  sc = svc->sysRestart();
385  if ( !sc.isSuccess() ) {
386  error() << "Unable to re-start Service: " << svc->name() << endmsg;
387  return StatusCode::FAILURE;
388  }
389  }
390  return StatusCode::SUCCESS;
391 }
392 
393 //------------------------------------------------------------------------------
395 //------------------------------------------------------------------------------
396 {
397  // make sure that HistogramDataSvc and THistSvc get finalized after the
398  // ToolSvc, and the FileMgr and StatusCodeSvc after that
399  int pri_tool = getPriority( "ToolSvc" );
400  if ( pri_tool != 0 ) {
401  setPriority( "THistSvc", pri_tool - 10 ).ignore();
402  setPriority( "ChronoStatSvc", pri_tool - 20 ).ignore();
403  setPriority( "AuditorSvc", pri_tool - 30 ).ignore();
404  setPriority( "NTupleSvc", pri_tool - 10 ).ignore();
405  setPriority( "HistogramDataSvc", pri_tool - 10 ).ignore();
406  // Preserve the relative ordering between HistogramDataSvc and HistogramPersistencySvc
407  setPriority( "HistogramPersistencySvc", pri_tool - 20 ).ignore();
408  setPriority( "HistorySvc", pri_tool - 30 ).ignore();
409  setPriority( "FileMgr", pri_tool - 40 ).ignore();
410  }
411 
412  // get list of PostFinalize clients
414  auto p_inc = service<IIncidentSvc>( "IncidentSvc", false );
415  if ( p_inc ) {
416  p_inc->getListeners( postFinList, IncidentType::SvcPostFinalize );
417  p_inc.reset();
418  }
419 
420  // make sure the StatusCodeSvc gets finalized really late:
421  setPriority( "StatusCodeSvc", -9999 ).ignore();
422 
423  // ensure that the list is ordered by priority
424  m_listsvc.sort();
425  // dump();
426 
427  StatusCode sc( StatusCode::SUCCESS, true );
428  {
429  // we work on a copy to avoid to operate twice on the services created on demand
430  // which are already in the correct state.
431  // only act on active services
432  // call finalize() for all services in reverse order
433  for ( const auto& svc : reverse( activeSvc( m_listsvc ) ) ) {
434  const std::string& name = svc->name();
435  // ignore the current state for the moment
436  // if( Gaudi::StateMachine::INITIALIZED == svc->state() )
437  DEBMSG << "Finalizing service " << name << endmsg;
438  if ( !svc->sysFinalize().isSuccess() ) {
439  warning() << "Finalization of service " << name << " failed" << endmsg;
440  sc = StatusCode::FAILURE;
441  }
442  }
443  }
444 
445  // call SvcPostFinalize on all clients
446  if ( !postFinList.empty() ) {
447  DEBMSG << "Will call SvcPostFinalize for " << postFinList.size() << " clients" << endmsg;
448  Incident inc( "ServiceManager", IncidentType::SvcPostFinalize );
449  for ( auto& itr : postFinList ) itr->handle( inc );
450  }
451 
452  // loop over all Active Services, removing them one by one.
453  // They should be deleted because the reference counting goes to 0.
454  DEBMSG << "Looping over all active services..." << endmsg;
455  auto it = m_listsvc.begin();
456  while ( it != m_listsvc.end() ) {
457  DEBMSG << "---- " << it->service->name() << " (refCount = " << it->service->refCount() << ")" << endmsg;
458  if ( it->service->refCount() < 1 ) {
459  warning() << "Too low reference count for " << it->service->name() << " (should not go below 1 at this point)"
460  << endmsg;
461  it->service->addRef();
462  }
463  if ( it->active ) {
464  it = m_listsvc.erase( it );
465  } else {
466  ++it;
467  }
468  }
469  return sc;
470 }
471 
472 //------------------------------------------------------------------------------
474  //------------------------------------------------------------------------------
475  auto it = find( name );
476  return ( it != m_listsvc.end() ) ? it->priority : 0;
477 }
478 
479 //------------------------------------------------------------------------------
481  //------------------------------------------------------------------------------
482  auto it = find( name );
483  if ( it == m_listsvc.end() ) return StatusCode::FAILURE;
484  it->priority = prio;
485  return StatusCode::SUCCESS;
486 }
487 
488 //------------------------------------------------------------------------------
489 // Get the value of the initialization loop check flag.
490 //------------------------------------------------------------------------------
492 //------------------------------------------------------------------------------
493 // Set the value of the initialization loop check flag.
494 //------------------------------------------------------------------------------
496 
497 //------------------------------------------------------------------------------
498 // Dump out contents of service list
499 //------------------------------------------------------------------------------
500 void ServiceManager::dump() const {
501 
502  auto& log = info();
503  log << "\n"
504  << "===================== listing all services ===================\n"
505  << " prior ref name active\n";
506 
507  for ( const auto& svc : m_listsvc ) {
508 
509  log.width( 6 );
510  log.flags( std::ios_base::right );
511  log << svc.priority << " ";
512  log.width( 5 );
513  log << svc.service->refCount() << " ";
514  log.width( 30 );
515  log.flags( std::ios_base::left );
516  log << svc.service->name() << " ";
517  log.width( 2 );
518  log << svc.active << std::endl;
519  }
520 
521  log << "=================================================================\n";
522  log << endmsg;
523 }
524 
526  resetMessaging();
527  for ( auto& svcItem : m_listsvc ) {
528  const auto svc = dynamic_cast<Service*>( svcItem.service.get() );
529  if ( svc ) svc->resetMessaging();
530  }
531 }
532 
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()
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:267
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:49
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...
constexpr static const auto SUCCESS
Definition: StatusCode.h:85
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:341
bool isFailure() const
Definition: StatusCode.h:130
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:76
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:130
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:50
Definition of the basic interface.
Definition: IInterface.h:244
~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:147
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:164
T clear(T...args)
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:153
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)
constexpr static const auto FAILURE
Definition: StatusCode.h:86
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:21
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:192
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).