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"
3 #include "GaudiKernel/IService.h"
6 #include "GaudiKernel/System.h"
7 #include "GaudiKernel/Service.h"
9 #include "GaudiKernel/SmartIF.h"
12 #include "GaudiKernel/Incident.h"
13 #include "GaudiKernel/reverse.h"
14 
15 #include <iostream>
16 #include <cassert>
17 #include <algorithm>
18 #include <functional>
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) {
33  std::vector<IService*> v; v.reserve(lst.size());
34  for(auto& i : lst) {
35  if (i.active) v.push_back(i.service.get());
36  }
37  return v;
38  }
39 }
40 
41 // constructor
43  base_class(application, IService::interfaceID()),
44  m_appSvc(application)
45 {
46  // Set the service locator to myself
47  m_svcLocator = this;
48  addRef(); // increase ref count, so we live forever...
49 }
50 
51 // destructor
53  //-- inform the orphan services that I am gone....
54  for (auto& svc : m_listsvc) svc.service->setServiceManager(nullptr);
55 }
56 
57 //------------------------------------------------------------------------------
58 // Instantiate a service
60 //------------------------------------------------------------------------------
61 {
62  // Check if the service is already existing
63  if(existsService(typeName.name())) {
64  // return an error because a service with that name already exists
65  return no_service;
66  }
67 
68  const std::string &name = typeName.name();
69  std::string type = typeName.type();
70  if (!typeName.haveType()) { // the type is not explicit
71  // see we have some specific type mapping for the name
72  auto it = m_maptype.find(typeName.name());
73  if( it != m_maptype.end() ) {
74  type = it->second; // use the declared type
75  }
76  }
77 
79  auto ip = type.find("__");
80  if ( ip != std::string::npos) type.erase(ip,type.length());
81 
82  IService* service = Service::Factory::create(type, name, this);
83  if ( !service ) {
84  fatal() << "No Service factory for " << type << " available." << endmsg;
85  return no_service;
86  }
87  // Check the compatibility of the version of the interface obtained
88  if( !isValidInterface(service) ) {
89  fatal() << "Incompatible interface IService version for " << type << endmsg;
90  return no_service;
91  }
92 
93  m_listsvc.push_back(service);
94  service->setServiceManager(this);
95  return m_listsvc.back().service; // DANGER: returns a reference to a SmartIF in m_listsvc, and hence does no longer 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 = createService(typeName); // WARNING: svc is now a reference to something that lives in m_listsvc
123  if (!svc) return StatusCode::FAILURE;
124  it = find(svc.get()); // now it is in the list because createService added it
125  it->priority = prio;
127  if (targetFSMState() >= Gaudi::StateMachine::INITIALIZED) { // WARNING: this can trigger a recursion!!!
128  sc = svc->sysInitialize();
130  sc = svc->sysStart();
131  }
132  }
133  if(sc.isFailure()) { // if initialization failed, remove it from the list
134  error() << "Unable to initialize service \"" << typeName.name() << "\""
135  << endmsg;
136  LockGuard_t lck(m_gLock);
137  m_listsvc.erase(it);
138  // Note: removing it from the list + the SmartIF going out of scope should trigger the delete
139  // delete svc.get();
140  return sc;
141  }
142  // initialization successful, we can work with the service
143  // Move the just initialized service to the back of the list
144  // (we care more about order of initialization than of creation)
145  LockGuard_t lck(m_gLock);
146  m_listsvc.push_back(*it);
147  m_listsvc.erase(it);
148  it = std::prev(std::end(m_listsvc)); // last entry (the iterator was invalidated by erase)
149  } else {
150  // if the service is already known, it is equivalent to a setPriority
151  it->priority = prio;
152  }
153  // 'it' is defined because either we found the service or we created it
154  // Now we can activate the service
155  it->active = true; // and make it active
156  return StatusCode(StatusCode::SUCCESS, true);
157 }
158 
159 //------------------------------------------------------------------------------
160 // Returns a smart pointer to a service.
162  const std::string &name = typeName.name();
163 
164  // Acquire the RAII lock to avoid simultaneous attempts from different threads to initialize a service
165 
166  Mutex_t *imut;
167  {
168  // get the global lock, then extract/create the service specific mutex
169  // then release global lock
170 
171  LockGuard_t lk(m_gLock);
172  auto mit = m_lockMap.find(name);
173  if (mit == m_lockMap.end()) {
174  mit = m_lockMap.emplace(name, std::unique_ptr<Mutex_t>( new Mutex_t )).first;
175  }
176  imut = mit->second.get();
177  }
178 
179  {
180  // now we have the service specific lock on the above mutex
181  LockGuard_t lk2(*imut);
182 
183  auto it = find(name);
184 
185  if (it != m_listsvc.end()) {
186  if (m_loopCheck &&
187  (createIf && it->service->FSMState() == Gaudi::StateMachine::CONFIGURED)) {
188  error()
189  << "Initialization loop detected when creating service \"" << name
190  << "\""
191  << endmsg;
192  return no_service;
193  }
194  return it->service;
195  }
196 
197  // Service not found. The user may be interested in one of the interfaces
198  // of the application manager itself
199  if( name == "ApplicationMgr" ||
200  name == "APPMGR" ||
201  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 {
221  [](ListSvc::const_reference i) {
222  return const_cast<IService*>(i.service.get());
223  });
224  return m_listOfPtrs;
225 }
226 
227 //------------------------------------------------------------------------------
229 //------------------------------------------------------------------------------
230 {
231  return find(name) != m_listsvc.end();
232 }
233 
234 //------------------------------------------------------------------------------
236 //------------------------------------------------------------------------------
237 {
238  auto it = find(svc);
239  if (it == m_listsvc.end()) return StatusCode(StatusCode::FAILURE,true);
240  m_listsvc.erase(it);
241  return StatusCode(StatusCode::SUCCESS,true);
242 }
243 
244 //------------------------------------------------------------------------------
246 //------------------------------------------------------------------------------
247 {
248  auto it = find(name);
249  if (it == m_listsvc.end()) return StatusCode::FAILURE;
250  m_listsvc.erase(it);
251  return StatusCode::SUCCESS;
252 }
253 
254 //------------------------------------------------------------------------------
256  const std::string& svctype )
257 //------------------------------------------------------------------------------
258 {
259  // once we get to C++17, replace with m_maptype.insert_or_assign...
260  auto p = m_maptype.emplace( svcname, svctype );
261  if ( !p.second ) p.first->second = svctype;
262  return StatusCode::SUCCESS;
263 }
264 
265 //------------------------------------------------------------------------------
267 //------------------------------------------------------------------------------
268 {
269  // ensure that the list is ordered by priority
270  m_listsvc.sort();
271  // we work on a copy to avoid to operate twice on the services created on demand
272  // which are already in the correct state.
273 
275  // call initialize() for all services
276  for (auto& it : activeSvc(m_listsvc) ) {
277  const std::string& name = it->name();
278  switch (it->FSMState()) {
280  DEBMSG << "Service " << name << " already initialized" << endmsg;
281  break;
283  DEBMSG << "Initializing service " << name << endmsg;
284  sc = it->sysInitialize();
285  if( !sc.isSuccess() ) {
286  error() << "Unable to initialize Service: " << name << endmsg;
287  return sc;
288  } break;
289  default:
290  error() << "Service " << name
291  << " not in the correct state to be initialized ("
292  << it->FSMState() << ")" << endmsg;
293  return StatusCode::FAILURE;
294  }
295  }
296  return StatusCode::SUCCESS;
297 }
298 
299 //------------------------------------------------------------------------------
301 //------------------------------------------------------------------------------
302 {
303  // ensure that the list is ordered by priority
304  m_listsvc.sort();
305  // we work on a copy to avoid to operate twice on the services created on demand
306  // (which are already in the correct state.
307  // only act on active services
309  // call initialize() for all services
310  for (auto& it : activeSvc(m_listsvc)) {
311  const std::string& name = it->name();
312  switch (it->FSMState()) {
314  DEBMSG << "Service " << name
315  << " already started" << endmsg;
316  break;
318  DEBMSG << "Starting service " << name << endmsg;
319  sc = it->sysStart();
320  if( !sc.isSuccess() ) {
321  error() << "Unable to start Service: " << name << endmsg;
322  return sc;
323  } break;
324  default:
325  error() << "Service " << name
326  << " not in the correct state to be started ("
327  << it->FSMState() << ")" << endmsg;
328  return StatusCode::FAILURE;
329  }
330  }
331  return StatusCode::SUCCESS;
332 }
333 
334 
335 //------------------------------------------------------------------------------
337 //------------------------------------------------------------------------------
338 {
339  // ensure that the list is ordered by priority
340  m_listsvc.sort();
341  // we work on a copy to avoid to operate twice on the services created on demand
342  // which are already in the correct state.
343  // only act on active services
344 
346  // call stop() for all services
347  for (const auto& svc : reverse(activeSvc(m_listsvc))) {
348  const std::string& name = svc->name();
349  switch (svc->FSMState()) {
351  DEBMSG << "Service " << name << " already stopped" << endmsg;
352  break;
354  DEBMSG << "Stopping service " << name << endmsg;
355  sc = svc->sysStop();
356  if( !sc.isSuccess() ) {
357  error() << "Unable to stop Service: " << name << endmsg;
358  return sc;
359  } break;
360  default:
361  DEBMSG << "Service " << name
362  << " not in the correct state to be stopped ("
363  << svc->FSMState() << ")" << endmsg;
364  return StatusCode::FAILURE;
365  }
366  }
367  return StatusCode::SUCCESS;
368 }
369 
370 //------------------------------------------------------------------------------
372 //------------------------------------------------------------------------------
373 {
374  // ensure that the list is ordered by priority
375  m_listsvc.sort();
376  // we work on a copy to avoid to operate twice on the services created on demand
377  // which are already in the correct state.
378  // only act on active services
380  // Re-Initialize all services
381  for (auto& svc : activeSvc(m_listsvc)) {
382  sc = svc->sysReinitialize();
383  if( !sc.isSuccess() ) {
384  error() << "Unable to re-initialize Service: " << svc->name() << endmsg;
385  return StatusCode::FAILURE;
386  }
387  }
388  return StatusCode::SUCCESS;
389 }
390 
391 //------------------------------------------------------------------------------
393 //------------------------------------------------------------------------------
394 {
395  // ensure that the list is ordered by priority
396  m_listsvc.sort();
397  // we work on a copy to avoid to operate twice on the services created on demand
398  // which are already in the correct state.
399  // only act on active services
401  // Re-Start all services
402  for (auto& svc : activeSvc(m_listsvc)) {
403  sc = svc->sysRestart();
404  if( !sc.isSuccess() ) {
405  error() << "Unable to re-start Service: " << svc->name() << endmsg;
406  return StatusCode::FAILURE;
407  }
408  }
409  return StatusCode::SUCCESS;
410 }
411 
412 //------------------------------------------------------------------------------
414 //------------------------------------------------------------------------------
415 {
416  // make sure that HistogramDataSvc and THistSvc get finalized after the
417  // ToolSvc, and the FileMgr and StatusCodeSvc after that
418  int pri_tool = getPriority("ToolSvc");
419  if (pri_tool != 0) {
420  setPriority("THistSvc",pri_tool-10).ignore();
421  setPriority("ChronoStatSvc",pri_tool-20).ignore();
422  setPriority("AuditorSvc",pri_tool-30).ignore();
423  setPriority("NTupleSvc",pri_tool-10).ignore();
424  setPriority("HistogramDataSvc",pri_tool-10).ignore();
425  // Preserve the relative ordering between HistogramDataSvc and HistogramPersistencySvc
426  setPriority("HistogramPersistencySvc",pri_tool-20).ignore();
427  setPriority("HistorySvc",pri_tool-30).ignore();
428  setPriority("FileMgr",pri_tool-40).ignore();
429  }
430 
431 
432  // get list of PostFinalize clients
434  auto p_inc = service<IIncidentSvc>("IncidentSvc",false);
435  if (p_inc) {
436  p_inc->getListeners(postFinList,IncidentType::SvcPostFinalize);
437  p_inc.reset();
438  }
439 
440  // make sure the StatusCodeSvc gets finalized really late:
441  setPriority("StatusCodeSvc",-9999).ignore();
442 
443  // ensure that the list is ordered by priority
444  m_listsvc.sort();
445  // dump();
446 
448  {
449  // we work on a copy to avoid to operate twice on the services created on demand
450  // which are already in the correct state.
451  // only act on active services
452  // call finalize() for all services in reverse order
453  for (const auto& svc : reverse(activeSvc(m_listsvc)) ) {
454  const std::string& name = svc->name();
455  // ignore the current state for the moment
456  // if( Gaudi::StateMachine::INITIALIZED == svc->state() )
457  DEBMSG << "Finalizing service " << name << endmsg;
458  if ( !svc->sysFinalize().isSuccess() ) {
459  warning() << "Finalization of service " << name << " failed" << endmsg;
460  sc = StatusCode::FAILURE;
461  }
462  }
463  }
464 
465  // call SvcPostFinalize on all clients
466  if (!postFinList.empty()) {
467  DEBMSG << "Will call SvcPostFinalize for " << postFinList.size() << " clients"
468  << endmsg;
469  Incident inc("ServiceManager", IncidentType::SvcPostFinalize);
470  for (auto& itr : postFinList) itr->handle(inc);
471  }
472 
473  // loop over all Active Services, removing them one by one.
474  // They should be deleted because the reference counting goes to 0.
475  DEBMSG << "Looping over all active services..." << endmsg;
476  auto it = m_listsvc.begin();
477  while (it != m_listsvc.end()) {
478  DEBMSG << "---- " << it->service->name()
479  << " (refCount = " << it->service->refCount() << ")"
480  << endmsg;
481  if (it->service->refCount() < 1) {
482  warning() << "Too low reference count for " << it->service->name()
483  << " (should not go below 1 at this point)" << endmsg;
484  it->service->addRef();
485  }
486  if (it->active) {
487  it = m_listsvc.erase(it);
488  } else {
489  ++it;
490  }
491  }
492  return sc;
493 }
494 
495 
496 //------------------------------------------------------------------------------
497 int
499 //------------------------------------------------------------------------------
500  auto it = find(name);
501  return (it != m_listsvc.end()) ? it->priority: 0;
502 }
503 
504 //------------------------------------------------------------------------------
507 //------------------------------------------------------------------------------
508  auto it = find(name);
509  if (it == m_listsvc.end()) return StatusCode::FAILURE;
510  it->priority = prio;
511  return StatusCode::SUCCESS;
512 }
513 
514 //------------------------------------------------------------------------------
515 // Get the value of the initialization loop check flag.
516 //------------------------------------------------------------------------------
518  return m_loopCheck;
519 }
520 //------------------------------------------------------------------------------
521 // Set the value of the initialization loop check flag.
522 //------------------------------------------------------------------------------
524  m_loopCheck = en;
525 }
526 
527 
528 //------------------------------------------------------------------------------
529 // Dump out contents of service list
530 //------------------------------------------------------------------------------
531 void ServiceManager::dump() const {
532 
533 
534  auto& log = info();
535  log << "\n"
536  << "===================== listing all services ===================\n"
537  << " prior ref name active\n";
538 
539  for (const auto& svc : m_listsvc) {
540 
541  log.width(6);
542  log.flags(std::ios_base::right);
543  log << svc.priority << " ";
544  log.width(5);
545  log << svc.service->refCount() << " ";
546  log.width(30);
547  log.flags(std::ios_base::left);
548  log << svc.service->name() << " ";
549  log.width(2);
550  log << svc.active << std::endl;
551 
552  }
553 
554  log << "=================================================================\n";
555  log << endmsg;
556 
557 }
558 
559 
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
StatusCode finalize() override
Finalize (from INITIALIZED to CONFIGURED).
std::pair< iterator, bool > emplace(Args &&...args)
Definition: Map.h:166
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
bool isSuccess() const
Test for a status code of SUCCESS.
Definition: StatusCode.h:74
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...
#define DECLARE_OBJECT_FACTORY(x)
Definition: ObjectFactory.h:17
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:323
bool isFailure() const
Test for a status code of FAILURE.
Definition: StatusCode.h:84
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:132
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:26
Definition of the basic interface.
Definition: IInterface.h:234
~ServiceManager() override
virtual destructor
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:149
const std::list< IService * > & getServices() const override
Return the list of Services.
StatusCode start() override
Start (from INITIALIZED to RUNNING).
T clear(T...args)
std::map< std::string, std::unique_ptr< Mutex_t > > m_lockMap
int getPriority(const std::string &name) const override
manage priorities of services
reverse_wrapper< T > reverse(T &&iterable)
Definition: reverse.h:32
T get(T...args)
T find(T...args)
T length(T...args)
STL class.
virtual StatusCode sysStart()=0
Start Service.
T begin(T...args)
T back_inserter(T...args)
const std::string & type() const
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
void ignore() const
Definition: StatusCode.h:106
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...
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:244
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).