ServiceManager.cpp
Go to the documentation of this file.
1 // Include files
2 #include "ServiceManager.h"
3 #include "GaudiKernel/IService.h"
4 #include "GaudiKernel/MsgStream.h"
5 #include "GaudiKernel/TypeNameString.h"
6 #include "GaudiKernel/System.h"
7 #include "GaudiKernel/Service.h"
8 #include "GaudiKernel/ObjectFactory.h"
9 #include "GaudiKernel/SmartIF.h"
10 #include "GaudiKernel/IIncidentSvc.h"
11 #include "GaudiKernel/IIncidentListener.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 = static_cast<ISvcLocator*>(this);
48 
49  addRef(); // Initial count set to 1
50 }
51 
52 // destructor
54  //-- inform the orphan services that I am gone....
55  for (auto& svc : m_listsvc) svc.service->setServiceManager(nullptr);
56 }
57 
58 //------------------------------------------------------------------------------
59 // Instantiate a service
61 //------------------------------------------------------------------------------
62 {
63  // Check if the service is already existing
64  if(existsService(typeName.name())) {
65  // return an error because a service with that name already exists
66  return no_service;
67  }
68 
69  const std::string &name = typeName.name();
70  std::string type = typeName.type();
71  if (!typeName.haveType()) { // the type is not explicit
72  // see we have some specific type mapping for the name
73  auto it = m_maptype.find(typeName.name());
74  if( it != m_maptype.end() ) {
75  type = it->second; // use the declared type
76  }
77  }
78 
80  auto ip = type.find("__");
81  if ( ip != std::string::npos) type.erase(ip,type.length());
82 
83  IService* service = Service::Factory::create(type, name, this);
84 
85  if ( service ) {
86  m_listsvc.push_back(service);
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  service->setServiceManager(this);
93  return m_listsvc.back().service; // DANGER: returns a reference to a SmartIF in m_listsvc, and hence does no longer allow relocations of those...
94  }
95  fatal() << "No Service factory for " << type << " available." << endmsg;
96  return no_service;
97 }
98 
99 //------------------------------------------------------------------------------
100 // add a service to the managed list
102 //------------------------------------------------------------------------------
103 {
104  auto it = find(svc);
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) {
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();
129  if (sc.isSuccess() && targetFSMState() >= Gaudi::StateMachine::RUNNING) {
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  m_listsvc.erase(it);
137  // Note: removing it from the list + the SmartIF going out of scope should trigger the delete
138  // delete svc.get();
139  return sc;
140  } else { // 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  m_listsvc.push_back(*it);
144  m_listsvc.erase(it);
145  it = std::prev(std::end(m_listsvc)); // last entry (the iterator was invalidated by erase)
146  }
147  } else {
148  return StatusCode::FAILURE;
149  }
150  } else {
151  // if the service is already known, it is equivalent to a setPriority
152  it->priority = prio;
153  }
154  // 'it' is defined because either we found the service or we created it
155  // Now we can activate the service
156  it->active = true; // and make it active
157  return StatusCode(StatusCode::SUCCESS, true);
158 }
159 
160 //------------------------------------------------------------------------------
161 // Returns a smart pointer to a service.
163  const std::string &name = typeName.name();
164 
165  // Acquire the RAII lock to avoid simultaneous attempts from different threads to initialize a service
166  std::lock_guard<std::recursive_mutex> lck(m_svcinitmutex);
167 
168  auto it = find(name);
169 
170  if (it != m_listsvc.end()) {
171  if (m_loopCheck &&
172  (createIf && it->service->FSMState() == Gaudi::StateMachine::CONFIGURED)) {
173  error()
174  << "Initialization loop detected when creating service \"" << name
175  << "\""
176  << endmsg;
177  return no_service;
178  }
179  return it->service;
180  } else {
181  // Service not found. The user may be interested in one of the interfaces
182  // of the application manager itself
183  if( name == "ApplicationMgr" ||
184  name == "APPMGR" ||
185  name == "" ) {
186  return m_appSvc;
187  } else if ( createIf ){
188  //last resort: we try to create the service
189  if (addService(typeName).isSuccess()){
190  return find(name)->service;
191  }
192  }
193  }
194  return no_service;
195 }
196 
197 //------------------------------------------------------------------------------
198 const std::list<IService*>& ServiceManager::getServices( ) const
199 //------------------------------------------------------------------------------
200 {
201  m_listOfPtrs.clear();
202  std::transform( std::begin(m_listsvc), std::end(m_listsvc),
203  std::back_inserter(m_listOfPtrs),
204  [](ListSvc::const_reference i) {
205  return const_cast<IService*>(i.service.get());
206  });
207  return m_listOfPtrs;
208 }
209 
210 //------------------------------------------------------------------------------
211 bool ServiceManager::existsService( const std::string& name) const
212 //------------------------------------------------------------------------------
213 {
214  return find(name) != m_listsvc.end();
215 }
216 
217 //------------------------------------------------------------------------------
219 //------------------------------------------------------------------------------
220 {
221  auto it = find(svc);
222  if (it != m_listsvc.end()) {
223  m_listsvc.erase(it);
224  return StatusCode(StatusCode::SUCCESS,true);
225  }
226  return StatusCode(StatusCode::FAILURE,true);
227 }
228 
229 //------------------------------------------------------------------------------
231 //------------------------------------------------------------------------------
232 {
233  auto it = find(name);
234  if (it != m_listsvc.end()) {
235  m_listsvc.erase(it);
236  return StatusCode::SUCCESS;
237  }
238  return StatusCode::FAILURE;
239 }
240 
241 //------------------------------------------------------------------------------
242 StatusCode ServiceManager::declareSvcType( const std::string& svcname,
243  const std::string& svctype )
244 //------------------------------------------------------------------------------
245 {
246  // once we get to C++17, replace with m_maptype.insert_or_assign...
247  auto p = m_maptype.emplace( svcname, svctype );
248  if ( !p.second ) p.first->second = svctype;
249  return StatusCode::SUCCESS;
250 }
251 
252 //------------------------------------------------------------------------------
254 //------------------------------------------------------------------------------
255 {
256  // ensure that the list is ordered by priority
257  m_listsvc.sort();
258  // we work on a copy to avoid to operate twice on the services created on demand
259  // which are already in the correct state.
260 
262  // call initialize() for all services
263  for (auto& it : activeSvc(m_listsvc) ) {
264  const std::string& name = it->name();
265  switch (it->FSMState()) {
267  DEBMSG << "Service " << name << " already initialized" << endmsg;
268  break;
270  DEBMSG << "Initializing service " << name << endmsg;
271  sc = it->sysInitialize();
272  if( !sc.isSuccess() ) {
273  error() << "Unable to initialize Service: " << name << endmsg;
274  return sc;
275  } break;
276  default:
277  error() << "Service " << name
278  << " not in the correct state to be initialized ("
279  << it->FSMState() << ")" << endmsg;
280  return StatusCode::FAILURE;
281  }
282  }
283  return StatusCode::SUCCESS;
284 }
285 
286 //------------------------------------------------------------------------------
288 //------------------------------------------------------------------------------
289 {
290  // ensure that the list is ordered by priority
291  m_listsvc.sort();
292  // we work on a copy to avoid to operate twice on the services created on demand
293  // (which are already in the correct state.
294  // only act on active services
296  // call initialize() for all services
297  for (auto& it : activeSvc(m_listsvc)) {
298  const std::string& name = it->name();
299  switch (it->FSMState()) {
301  DEBMSG << "Service " << name
302  << " already started" << endmsg;
303  break;
305  DEBMSG << "Starting service " << name << endmsg;
306  sc = it->sysStart();
307  if( !sc.isSuccess() ) {
308  error() << "Unable to start Service: " << name << endmsg;
309  return sc;
310  } break;
311  default:
312  error() << "Service " << name
313  << " not in the correct state to be started ("
314  << it->FSMState() << ")" << endmsg;
315  return StatusCode::FAILURE;
316  }
317  }
318  return StatusCode::SUCCESS;
319 }
320 
321 
322 //------------------------------------------------------------------------------
324 //------------------------------------------------------------------------------
325 {
326  // ensure that the list is ordered by priority
327  m_listsvc.sort();
328  // we work on a copy to avoid to operate twice on the services created on demand
329  // which are already in the correct state.
330  // only act on active services
331 
333  // call stop() for all services
334  for (const auto& svc : reverse(activeSvc(m_listsvc))) {
335  const std::string& name = svc->name();
336  switch (svc->FSMState()) {
338  DEBMSG << "Service " << name << " already stopped" << endmsg;
339  break;
341  DEBMSG << "Stopping service " << name << endmsg;
342  sc = svc->sysStop();
343  if( !sc.isSuccess() ) {
344  error() << "Unable to stop Service: " << name << endmsg;
345  return sc;
346  } break;
347  default:
348  DEBMSG << "Service " << name
349  << " not in the correct state to be stopped ("
350  << svc->FSMState() << ")" << endmsg;
351  return StatusCode::FAILURE;
352  }
353  }
354  return StatusCode::SUCCESS;
355 }
356 
357 //------------------------------------------------------------------------------
359 //------------------------------------------------------------------------------
360 {
361  // ensure that the list is ordered by priority
362  m_listsvc.sort();
363  // we work on a copy to avoid to operate twice on the services created on demand
364  // which are already in the correct state.
365  // only act on active services
367  // Re-Initialize all services
368  for (auto& svc : activeSvc(m_listsvc)) {
369  sc = svc->sysReinitialize();
370  if( !sc.isSuccess() ) {
371  error() << "Unable to re-initialize Service: " << svc->name() << endmsg;
372  return StatusCode::FAILURE;
373  }
374  }
375  return StatusCode::SUCCESS;
376 }
377 
378 //------------------------------------------------------------------------------
380 //------------------------------------------------------------------------------
381 {
382  // ensure that the list is ordered by priority
383  m_listsvc.sort();
384  // we work on a copy to avoid to operate twice on the services created on demand
385  // which are already in the correct state.
386  // only act on active services
388  // Re-Start all services
389  for (auto& svc : activeSvc(m_listsvc)) {
390  sc = svc->sysRestart();
391  if( !sc.isSuccess() ) {
392  error() << "Unable to re-start Service: " << svc->name() << endmsg;
393  return StatusCode::FAILURE;
394  }
395  }
396  return StatusCode::SUCCESS;
397 }
398 
399 //------------------------------------------------------------------------------
401 //------------------------------------------------------------------------------
402 {
403  // make sure that HistogramDataSvc and THistSvc get finalized after the
404  // ToolSvc, and the FileMgr and StatusCodeSvc after that
405  int pri_tool = getPriority("ToolSvc");
406  if (pri_tool != 0) {
407  setPriority("THistSvc",pri_tool-10).ignore();
408  setPriority("ChronoStatSvc",pri_tool-20).ignore();
409  setPriority("AuditorSvc",pri_tool-30).ignore();
410  setPriority("NTupleSvc",pri_tool-10).ignore();
411  setPriority("HistogramDataSvc",pri_tool-10).ignore();
412  // Preserve the relative ordering between HistogramDataSvc and HistogramPersistencySvc
413  setPriority("HistogramPersistencySvc",pri_tool-20).ignore();
414  setPriority("HistorySvc",pri_tool-30).ignore();
415  setPriority("FileMgr",pri_tool-40).ignore();
416  }
417 
418 
419  // get list of PostFinalize clients
420  std::vector<IIncidentListener*> postFinList;
421  {
422  auto p_inc = service<IIncidentSvc>("IncidentSvc",false);
423  if (p_inc) {
424  p_inc->getListeners(postFinList,IncidentType::SvcPostFinalize);
425  }
426  }
427 
428  // make sure the StatusCodeSvc gets finalized really late:
429  setPriority("StatusCodeSvc",-9999).ignore();
430 
431  // ensure that the list is ordered by priority
432  m_listsvc.sort();
433  // dump();
434 
436  {
437  // we work on a copy to avoid to operate twice on the services created on demand
438  // which are already in the correct state.
439  // only act on active services
440  // call finalize() for all services in reverse order
441  for (const auto& svc : reverse(activeSvc(m_listsvc)) ) {
442  const std::string& name = svc->name();
443  // ignore the current state for the moment
444  // if( Gaudi::StateMachine::INITIALIZED == svc->state() )
445  DEBMSG << "Finalizing service " << name << endmsg;
446  if ( !svc->sysFinalize().isSuccess() ) {
447  warning() << "Finalization of service " << name << " failed" << endmsg;
448  sc = StatusCode::FAILURE;
449  }
450  }
451  }
452 
453  // call SvcPostFinalize on all clients
454  if (!postFinList.empty()) {
455  DEBMSG << "Will call SvcPostFinalize for " << postFinList.size() << " clients"
456  << endmsg;
457  Incident inc("ServiceManager", IncidentType::SvcPostFinalize);
458  for (auto& itr : postFinList) itr->handle(inc);
459  }
460 
461  // loop over all Active Services, removing them one by one.
462  // They should be deleted because the reference counting goes to 0.
463  DEBMSG << "Looping over all active services..." << endmsg;
464  auto it = m_listsvc.begin();
465  while (it != m_listsvc.end()) {
466  DEBMSG << "---- " << it->service->name()
467  << " (refCount = " << it->service->refCount() << ")"
468  << endmsg;
469  if (it->service->refCount() < 1) {
470  warning() << "Too low reference count for " << it->service->name()
471  << " (should not go below 1 at this point)" << 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 
484 //------------------------------------------------------------------------------
485 int
486 ServiceManager::getPriority(const std::string& name) const {
487 //------------------------------------------------------------------------------
488  auto it = find(name);
489  return (it != m_listsvc.end()) ? it->priority: 0;
490 }
491 
492 //------------------------------------------------------------------------------
494 ServiceManager::setPriority(const std::string& name, int prio) {
495 //------------------------------------------------------------------------------
496  auto it = find(name);
497  if (it == m_listsvc.end()) return StatusCode::FAILURE;
498  it->priority = prio;
499  return StatusCode::SUCCESS;
500 }
501 
502 //------------------------------------------------------------------------------
503 // Get the value of the initialization loop check flag.
504 //------------------------------------------------------------------------------
506  return m_loopCheck;
507 }
508 //------------------------------------------------------------------------------
509 // Set the value of the initialization loop check flag.
510 //------------------------------------------------------------------------------
512  m_loopCheck = en;
513 }
514 
515 
516 //------------------------------------------------------------------------------
517 // Dump out contents of service list
518 //------------------------------------------------------------------------------
519 void ServiceManager::dump() const {
520 
521  MsgStream log(msgSvc(),name());
522 
523  log << MSG::INFO << "\n"
524  << "===================== listing all services ===================\n"
525  << " prior ref name active\n";
526 
527  for (const auto& svc : m_listsvc) {
528 
529  log.width(6);
530  log.flags(std::ios_base::right);
531  log << svc.priority << " ";
532  log.width(5);
533  log << svc.service->refCount() << " ";
534  log.width(30);
535  log.flags(std::ios_base::left);
536  log << svc.service->name() << " ";
537  log.width(2);
538  log << svc.active << std::endl;
539 
540  }
541 
542  log << "=================================================================\n";
543  log << endmsg;
544 
545 }
546 
547 
bool isValidInterface(I *i)
Templated function that throws an exception if the version if the interface implemented by the object...
Definition: IInterface.h:323
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()
Definition of the MsgStream class used to transmit messages.
Definition: MsgStream.h:24
void setLoopCheckEnabled(bool en) override
Set the value of the initialization loop check flag.
SmartIF< IService > m_appSvc
Pointer to the application IService interface.
reverse_wrapper< T > reverse(T &&iterable)
Definition: reverse.h:30
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
StatusCode finalize() override
Finalize (from INITIALIZED to CONFIGURED).
const std::string & name() const
Return the name of the manager (implementation of INamedInterface)
std::pair< iterator, bool > emplace(Args &&...args)
Definition: Map.h:166
int getPriority(const std::string &name) const override
manage priorities of services
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:244
auto begin(reverse_wrapper< T > &w)
Definition: reverse.h:45
bool isSuccess() const
Test for a status code of SUCCESS.
Definition: StatusCode.h:76
bool m_loopCheck
Check for service initialization loops.
ServiceManager(IInterface *application)
default creator
virtual const std::list< IService * > & getServices() const
Return the list of Services.
StatusCode restart() override
Initialization (from RUNNING to RUNNING, via INITIALIZED).
#define DECLARE_OBJECT_FACTORY(x)
Definition: ObjectFactory.h:17
const std::string SvcPostFinalize
ONLY For Services that need something after they've been finalized.
Definition: Incident.h:91
bool isFailure() const
Test for a status code of FAILURE.
Definition: StatusCode.h:86
MapType m_maptype
Map of service name and service type.
TYPE * get() const
Get interface pointer.
Definition: SmartIF.h:76
virtual StatusCode sysInitialize()=0
Initialize Service.
StatusCode stop() override
Stop (from RUNNING to INITIALIZED).
iterator end()
Definition: Map.h:132
Helper class to parse a string of format "type/name".
Definition: TypeNameString.h:9
void dump() const
std::recursive_mutex m_svcinitmutex
Mutex to synchronize shared service initialization between threads.
auto end(reverse_wrapper< T > &w)
Definition: reverse.h:47
bool loopCheckEnabled() const override
Get the value of the initialization loop check flag.
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
iterator find(const key_type &key)
Definition: Map.h:149
StatusCode start() override
Start (from INITIALIZED to RUNNING).
virtual bool existsService(const std::string &name) const
implementation of ISvcLocation::existsService
virtual StatusCode sysStart()=0
Start Service.
Base class used to extend a class implementing other interfaces.
Definition: extends.h:10
long flags() const
IOS emulation.
Definition: MsgStream.h:177
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:16
int width() const
Definition: MsgStream.h:186
ListSvc::iterator find(const std::string &name)
StatusCode declareSvcType(const std::string &svcname, const std::string &svctype) override
implementation of ISvcManager::declareSvcType
#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:108
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 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...
list i
Definition: ana.py:128
string type
Definition: gaudirun.py:151
StatusCode addService(IService *svc, int prio=DEFAULT_SVC_PRIORITY) override
implementation of ISvcManager::addService
StatusCode initialize() override
Initialization (from CONFIGURED to INITIALIZED).