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 = 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  auto it = find(svc);
104  if (it != m_listsvc.end()) {
105  it->priority = prio; // if the service is already known, it is equivalent to a setPriority
106  it->active = true; // and make it active
107  } else {
108  m_listsvc.emplace_back(svc,prio,true);
109  }
110  return StatusCode::SUCCESS;
111 }
112 
113 //------------------------------------------------------------------------------
114 // add the service with the give type and name to the active list
116 //------------------------------------------------------------------------------
117 {
118  auto it = find(typeName.name()); // try to find the service by name
119  if (it == m_listsvc.end()) { // not found
120  // If the service does not exist, we create it
121  SmartIF<IService>& svc = createService(typeName); // WARNING: svc is now a reference to something that lives in m_listsvc
122  if (!svc) return StatusCode::FAILURE;
123  it = find(svc.get()); // now it is in the list because createService added it
124  it->priority = prio;
126  if (targetFSMState() >= Gaudi::StateMachine::INITIALIZED) { // WARNING: this can trigger a recursion!!!
127  sc = svc->sysInitialize();
128  if (sc.isSuccess() && targetFSMState() >= Gaudi::StateMachine::RUNNING) {
129  sc = svc->sysStart();
130  }
131  }
132  if(sc.isFailure()) { // if initialization failed, remove it from the list
133  error() << "Unable to initialize service \"" << typeName.name() << "\""
134  << endmsg;
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  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  } else {
147  // if the service is already known, it is equivalent to a setPriority
148  it->priority = prio;
149  }
150  // 'it' is defined because either we found the service or we created it
151  // Now we can activate the service
152  it->active = true; // and make it active
153  return StatusCode(StatusCode::SUCCESS, true);
154 }
155 
156 //------------------------------------------------------------------------------
157 // Returns a smart pointer to a service.
159  const std::string &name = typeName.name();
160 
161  // Acquire the RAII lock to avoid simultaneous attempts from different threads to initialize a service
162  std::lock_guard<std::recursive_mutex> lck(m_svcinitmutex);
163 
164  auto it = find(name);
165 
166  if (it != m_listsvc.end()) {
167  if (m_loopCheck &&
168  (createIf && it->service->FSMState() == Gaudi::StateMachine::CONFIGURED)) {
169  error()
170  << "Initialization loop detected when creating service \"" << name
171  << "\""
172  << endmsg;
173  return no_service;
174  }
175  return it->service;
176  }
177 
178  // Service not found. The user may be interested in one of the interfaces
179  // of the application manager itself
180  if( name == "ApplicationMgr" ||
181  name == "APPMGR" ||
182  name == "" ) {
183  return m_appSvc;
184  }
185 
186  //last resort: we try to create the service
187  if ( createIf && addService(typeName).isSuccess()){
188  return find(name)->service;
189  }
190 
191  return no_service;
192 }
193 
194 //------------------------------------------------------------------------------
195 const std::list<IService*>& ServiceManager::getServices( ) const
196 //------------------------------------------------------------------------------
197 {
198  m_listOfPtrs.clear();
199  std::transform( std::begin(m_listsvc), std::end(m_listsvc),
200  std::back_inserter(m_listOfPtrs),
201  [](ListSvc::const_reference i) {
202  return const_cast<IService*>(i.service.get());
203  });
204  return m_listOfPtrs;
205 }
206 
207 //------------------------------------------------------------------------------
208 bool ServiceManager::existsService( const std::string& name) const
209 //------------------------------------------------------------------------------
210 {
211  return find(name) != m_listsvc.end();
212 }
213 
214 //------------------------------------------------------------------------------
216 //------------------------------------------------------------------------------
217 {
218  auto it = find(svc);
219  if (it == m_listsvc.end()) return StatusCode(StatusCode::FAILURE,true);
220  m_listsvc.erase(it);
221  return StatusCode(StatusCode::SUCCESS,true);
222 }
223 
224 //------------------------------------------------------------------------------
226 //------------------------------------------------------------------------------
227 {
228  auto it = find(name);
229  if (it == m_listsvc.end()) return StatusCode::FAILURE;
230  m_listsvc.erase(it);
231  return StatusCode::SUCCESS;
232 }
233 
234 //------------------------------------------------------------------------------
235 StatusCode ServiceManager::declareSvcType( const std::string& svcname,
236  const std::string& svctype )
237 //------------------------------------------------------------------------------
238 {
239  // once we get to C++17, replace with m_maptype.insert_or_assign...
240  auto p = m_maptype.emplace( svcname, svctype );
241  if ( !p.second ) p.first->second = svctype;
242  return StatusCode::SUCCESS;
243 }
244 
245 //------------------------------------------------------------------------------
247 //------------------------------------------------------------------------------
248 {
249  // ensure that the list is ordered by priority
250  m_listsvc.sort();
251  // we work on a copy to avoid to operate twice on the services created on demand
252  // which are already in the correct state.
253 
255  // call initialize() for all services
256  for (auto& it : activeSvc(m_listsvc) ) {
257  const std::string& name = it->name();
258  switch (it->FSMState()) {
260  DEBMSG << "Service " << name << " already initialized" << endmsg;
261  break;
263  DEBMSG << "Initializing service " << name << endmsg;
264  sc = it->sysInitialize();
265  if( !sc.isSuccess() ) {
266  error() << "Unable to initialize Service: " << name << endmsg;
267  return sc;
268  } break;
269  default:
270  error() << "Service " << name
271  << " not in the correct state to be initialized ("
272  << it->FSMState() << ")" << endmsg;
273  return StatusCode::FAILURE;
274  }
275  }
276  return StatusCode::SUCCESS;
277 }
278 
279 //------------------------------------------------------------------------------
281 //------------------------------------------------------------------------------
282 {
283  // ensure that the list is ordered by priority
284  m_listsvc.sort();
285  // we work on a copy to avoid to operate twice on the services created on demand
286  // (which are already in the correct state.
287  // only act on active services
289  // call initialize() for all services
290  for (auto& it : activeSvc(m_listsvc)) {
291  const std::string& name = it->name();
292  switch (it->FSMState()) {
294  DEBMSG << "Service " << name
295  << " already started" << endmsg;
296  break;
298  DEBMSG << "Starting service " << name << endmsg;
299  sc = it->sysStart();
300  if( !sc.isSuccess() ) {
301  error() << "Unable to start Service: " << name << endmsg;
302  return sc;
303  } break;
304  default:
305  error() << "Service " << name
306  << " not in the correct state to be started ("
307  << it->FSMState() << ")" << endmsg;
308  return StatusCode::FAILURE;
309  }
310  }
311  return StatusCode::SUCCESS;
312 }
313 
314 
315 //------------------------------------------------------------------------------
317 //------------------------------------------------------------------------------
318 {
319  // ensure that the list is ordered by priority
320  m_listsvc.sort();
321  // we work on a copy to avoid to operate twice on the services created on demand
322  // which are already in the correct state.
323  // only act on active services
324 
326  // call stop() for all services
327  for (const auto& svc : reverse(activeSvc(m_listsvc))) {
328  const std::string& name = svc->name();
329  switch (svc->FSMState()) {
331  DEBMSG << "Service " << name << " already stopped" << endmsg;
332  break;
334  DEBMSG << "Stopping service " << name << endmsg;
335  sc = svc->sysStop();
336  if( !sc.isSuccess() ) {
337  error() << "Unable to stop Service: " << name << endmsg;
338  return sc;
339  } break;
340  default:
341  DEBMSG << "Service " << name
342  << " not in the correct state to be stopped ("
343  << svc->FSMState() << ")" << endmsg;
344  return StatusCode::FAILURE;
345  }
346  }
347  return StatusCode::SUCCESS;
348 }
349 
350 //------------------------------------------------------------------------------
352 //------------------------------------------------------------------------------
353 {
354  // ensure that the list is ordered by priority
355  m_listsvc.sort();
356  // we work on a copy to avoid to operate twice on the services created on demand
357  // which are already in the correct state.
358  // only act on active services
360  // Re-Initialize all services
361  for (auto& svc : activeSvc(m_listsvc)) {
362  sc = svc->sysReinitialize();
363  if( !sc.isSuccess() ) {
364  error() << "Unable to re-initialize Service: " << svc->name() << endmsg;
365  return StatusCode::FAILURE;
366  }
367  }
368  return StatusCode::SUCCESS;
369 }
370 
371 //------------------------------------------------------------------------------
373 //------------------------------------------------------------------------------
374 {
375  // ensure that the list is ordered by priority
376  m_listsvc.sort();
377  // we work on a copy to avoid to operate twice on the services created on demand
378  // which are already in the correct state.
379  // only act on active services
381  // Re-Start all services
382  for (auto& svc : activeSvc(m_listsvc)) {
383  sc = svc->sysRestart();
384  if( !sc.isSuccess() ) {
385  error() << "Unable to re-start Service: " << svc->name() << endmsg;
386  return StatusCode::FAILURE;
387  }
388  }
389  return StatusCode::SUCCESS;
390 }
391 
392 //------------------------------------------------------------------------------
394 //------------------------------------------------------------------------------
395 {
396  // make sure that HistogramDataSvc and THistSvc get finalized after the
397  // ToolSvc, and the FileMgr and StatusCodeSvc after that
398  int pri_tool = getPriority("ToolSvc");
399  if (pri_tool != 0) {
400  setPriority("THistSvc",pri_tool-10).ignore();
401  setPriority("ChronoStatSvc",pri_tool-20).ignore();
402  setPriority("AuditorSvc",pri_tool-30).ignore();
403  setPriority("NTupleSvc",pri_tool-10).ignore();
404  setPriority("HistogramDataSvc",pri_tool-10).ignore();
405  // Preserve the relative ordering between HistogramDataSvc and HistogramPersistencySvc
406  setPriority("HistogramPersistencySvc",pri_tool-20).ignore();
407  setPriority("HistorySvc",pri_tool-30).ignore();
408  setPriority("FileMgr",pri_tool-40).ignore();
409  }
410 
411 
412  // get list of PostFinalize clients
413  std::vector<IIncidentListener*> postFinList;
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 
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"
448  << endmsg;
449  Incident inc("ServiceManager", IncidentType::SvcPostFinalize);
450  for (auto& itr : postFinList) itr->handle(inc);
451  }
452 
453  // loop over all Active Services, removing them one by one.
454  // They should be deleted because the reference counting goes to 0.
455  DEBMSG << "Looping over all active services..." << endmsg;
456  auto it = m_listsvc.begin();
457  while (it != m_listsvc.end()) {
458  DEBMSG << "---- " << it->service->name()
459  << " (refCount = " << it->service->refCount() << ")"
460  << endmsg;
461  if (it->service->refCount() < 1) {
462  warning() << "Too low reference count for " << it->service->name()
463  << " (should not go below 1 at this point)" << endmsg;
464  it->service->addRef();
465  }
466  if (it->active) {
467  it = m_listsvc.erase(it);
468  } else {
469  ++it;
470  }
471  }
472  return sc;
473 }
474 
475 
476 //------------------------------------------------------------------------------
477 int
478 ServiceManager::getPriority(const std::string& name) const {
479 //------------------------------------------------------------------------------
480  auto it = find(name);
481  return (it != m_listsvc.end()) ? it->priority: 0;
482 }
483 
484 //------------------------------------------------------------------------------
486 ServiceManager::setPriority(const std::string& name, int prio) {
487 //------------------------------------------------------------------------------
488  auto it = find(name);
489  if (it == m_listsvc.end()) return StatusCode::FAILURE;
490  it->priority = prio;
491  return StatusCode::SUCCESS;
492 }
493 
494 //------------------------------------------------------------------------------
495 // Get the value of the initialization loop check flag.
496 //------------------------------------------------------------------------------
498  return m_loopCheck;
499 }
500 //------------------------------------------------------------------------------
501 // Set the value of the initialization loop check flag.
502 //------------------------------------------------------------------------------
504  m_loopCheck = en;
505 }
506 
507 
508 //------------------------------------------------------------------------------
509 // Dump out contents of service list
510 //------------------------------------------------------------------------------
511 void ServiceManager::dump() const {
512 
513  MsgStream log(msgSvc(),name());
514 
515  log << MSG::INFO << "\n"
516  << "===================== listing all services ===================\n"
517  << " prior ref name active\n";
518 
519  for (const auto& svc : m_listsvc) {
520 
521  log.width(6);
522  log.flags(std::ios_base::right);
523  log << svc.priority << " ";
524  log.width(5);
525  log << svc.service->refCount() << " ";
526  log.width(30);
527  log.flags(std::ios_base::left);
528  log << svc.service->name() << " ";
529  log.width(2);
530  log << svc.active << std::endl;
531 
532  }
533 
534  log << "=================================================================\n";
535  log << endmsg;
536 
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()
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
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:244
StatusCode finalize() override
Finalize (from INITIALIZED to CONFIGURED).
std::pair< iterator, bool > emplace(Args &&...args)
Definition: Map.h:166
int getPriority(const std::string &name) const override
manage priorities of services
bool isSuccess() const
Test for a status code of SUCCESS.
Definition: StatusCode.h:76
auto begin(reverse_wrapper< T > &w)
Definition: reverse.h:45
bool m_loopCheck
Check for service initialization loops.
bool existsService(const std::string &name) const override
implementation of ISvcLocation::existsService
ServiceManager(IInterface *application)
default creator
StatusCode restart() override
Initialization (from RUNNING to RUNNING, via INITIALIZED).
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.
#define DECLARE_OBJECT_FACTORY(x)
Definition: ObjectFactory.h:17
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.
bool loopCheckEnabled() const override
Get the value of the initialization loop check flag.
General service interface definition.
Definition: IService.h:18
auto end(reverse_wrapper< T > &w)
Definition: reverse.h:47
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:26
Definition of the basic interface.
Definition: IInterface.h:234
const std::list< IService * > & getServices() const override
Return the list of Services.
~ServiceManager() override
virtual destructor
iterator find(const key_type &key)
Definition: Map.h:149
const std::string & name() const override
Return the name of the manager (implementation of INamedInterface)
StatusCode start() override
Start (from INITIALIZED to RUNNING).
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
bool isValidInterface(I *i)
Templated function that throws an exception if the version if the interface implemented by the object...
Definition: IInterface.h:323
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).