The Gaudi Framework  master (82fdf313)
Loading...
Searching...
No Matches
ServiceManager.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11
12#include "ServiceManager.h"
19#include <GaudiKernel/Service.h>
20#include <GaudiKernel/SmartIF.h>
21#include <GaudiKernel/System.h>
23#include <GaudiKernel/reverse.h>
24#include <algorithm>
25#include <cassert>
26#include <iostream>
27
28#define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
29#define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
30
31#define DEBMSG ON_DEBUG debug()
32#define VERMSG ON_VERBOSE verbose()
33
35static SmartIF<IService> no_service;
36
38namespace {
39 template <typename C>
40 std::vector<IService*> activeSvc( const C& lst ) {
41 std::vector<IService*> v;
42 v.reserve( lst.size() );
43 for ( auto& i : lst ) {
44 if ( i.active ) v.push_back( i.service.get() );
45 }
46 return v;
47 }
48} // namespace
49
51 : base_class( application, IService::interfaceID() ), m_appSvc( application ) {
52 // Set the service locator to myself
53 m_svcLocator = this;
54 addRef(); // increase ref count, so we live forever...
55}
56
58 //-- inform the orphan services that I am gone....
59 for ( auto& svc : m_listsvc ) svc.service->setServiceManager( nullptr );
60}
61
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 ).release();
84 if ( !service ) {
85 fatal() << "No Service factory for " << type << " available." << endmsg;
86 return no_service;
87 }
88 // Check the compatibility of the version of the interface obtained
89 if ( !isValidInterface( service ) ) {
90 fatal() << "Incompatible interface IService version for " << type << endmsg;
91 return no_service;
92 }
93
94 if ( name == "JobOptionsSvc" ) {
95 if ( !dynamic_cast<Gaudi::Interfaces::IOptionsSvc*>( service ) ) {
96 fatal() << typeName << " does not implement Gaudi::Interfaces::IOptionsSvc" << endmsg;
97 return no_service;
98 }
99 }
100
101 auto lck = std::scoped_lock{ m_gLock };
102 m_listsvc.push_back( service );
103 service->setServiceManager( this );
104 return m_listsvc.back().service; // DANGER: returns a reference to a SmartIF in m_listsvc, and hence does no longer
105 // allow relocations of those...
106}
107
109 auto it = find( svc );
110 auto lck = std::scoped_lock{ m_gLock };
111 if ( it != m_listsvc.end() ) {
112 it->priority = prio; // if the service is already known, it is equivalent to a setPriority
113 it->active = true; // and make it active
114 } else {
115 m_listsvc.emplace_back( svc, prio, true );
116 }
117 return StatusCode::SUCCESS;
118}
119
121 auto it = find( typeName.name() ); // try to find the service by name
122 if ( it == m_listsvc.end() ) { // not found
123 // If the service does not exist, we create it
124 SmartIF<IService>& svc =
125 createService( typeName ); // WARNING: svc is now a reference to something that lives in m_listsvc
126 if ( !svc ) return StatusCode::FAILURE;
127 it = find( svc.get() ); // now it is in the list because createService added it
128 it->priority = prio;
130 if ( targetFSMState() >= Gaudi::StateMachine::INITIALIZED ) { // WARNING: this can trigger a recursion!!!
131 sc = svc->sysInitialize();
132 if ( sc.isSuccess() && targetFSMState() >= Gaudi::StateMachine::RUNNING ) { sc = svc->sysStart(); }
133 }
134 if ( sc.isFailure() ) { // if initialization failed, remove it from the list
135 error() << "Unable to initialize service \"" << typeName.name() << "\"" << endmsg;
136 auto lck = std::scoped_lock{ 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 auto lck = std::scoped_lock{ 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::SUCCESS;
157}
158
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 auto* imut = [&] {
165 // get the global lock, then extract/create the service specific mutex
166 // then release global lock
167
168 auto lk = std::scoped_lock{ this->m_gLock };
169 auto mit = m_lockMap.find( name );
170 if ( mit == m_lockMap.end() ) {
171 mit = m_lockMap.emplace( std::piecewise_construct_t{}, std::forward_as_tuple( name ), std::forward_as_tuple() )
172 .first;
173 }
174 return &mit->second;
175 }();
176
177 {
178 // now we have the service specific lock on the above mutex
179 auto lk2 = std::scoped_lock{ *imut };
180
181 auto it = find( name );
182
183 if ( it != m_listsvc.end() ) {
184 if ( m_loopCheck && ( createIf && it->service->FSMState() == Gaudi::StateMachine::CONFIGURED ) ) {
185 error() << "Initialization loop detected when creating service \"" << name << "\"" << endmsg;
186 return no_service;
187 }
188 return it->service;
189 }
190
191 // Service not found. The user may be interested in one of the interfaces
192 // of the application manager itself
193 if ( name == "ApplicationMgr" || name == "APPMGR" || name == "" ) { return m_appSvc; }
194
195 // last resort: we try to create the service
196 if ( createIf && addService( typeName ).isSuccess() ) { return find( name )->service; }
197
198 return no_service;
199 }
200}
201
202const std::list<IService*>& ServiceManager::getServices() const {
203 m_listOfPtrs.clear();
204 std::transform( std::begin( m_listsvc ), std::end( m_listsvc ), std::back_inserter( m_listOfPtrs ),
205 []( ListSvc::const_reference i ) { return i.service.get(); } );
206 return m_listOfPtrs;
207}
208
209bool ServiceManager::existsService( std::string_view name ) const { return find( name ) != m_listsvc.end(); }
210
212 auto it = find( svc );
213 if ( it == m_listsvc.end() ) return StatusCode::FAILURE;
214 m_listsvc.erase( it );
215 return StatusCode::SUCCESS;
216}
217
219 auto it = find( name );
220 if ( it == m_listsvc.end() ) return StatusCode::FAILURE;
221 m_listsvc.erase( it );
222 return StatusCode::SUCCESS;
223}
224
225StatusCode ServiceManager::declareSvcType( std::string svcname, std::string svctype ) {
226 m_maptype.insert_or_assign( std::move( svcname ), std::move( svctype ) );
227 return StatusCode::SUCCESS;
228}
229
231 // ensure that the list is ordered by priority
232 m_listsvc.sort();
233 // we work on a copy to avoid to operate twice on the services created on demand
234 // which are already in the correct state.
235
237 // call initialize() for all services
238 for ( auto& it : activeSvc( m_listsvc ) ) {
239 const std::string& name = it->name();
240 switch ( it->FSMState() ) {
242 DEBMSG << "Service " << name << " already initialized" << endmsg;
243 break;
245 DEBMSG << "Initializing service " << name << endmsg;
246 sc = it->sysInitialize();
247 if ( !sc.isSuccess() ) {
248 error() << "Unable to initialize Service: " << name << endmsg;
249 return sc;
250 }
251 break;
252 default:
253 error() << "Service " << name << " not in the correct state to be initialized (" << it->FSMState() << ")"
254 << endmsg;
255 return StatusCode::FAILURE;
256 }
257 }
258 return StatusCode::SUCCESS;
259}
260
262 // ensure that the list is ordered by priority
263 m_listsvc.sort();
264 // we work on a copy to avoid to operate twice on the services created on demand
265 // (which are already in the correct state.
266 // only act on active services
268 // call initialize() for all services
269 for ( auto& it : activeSvc( m_listsvc ) ) {
270 const std::string& name = it->name();
271 switch ( it->FSMState() ) {
273 DEBMSG << "Service " << name << " already started" << endmsg;
274 break;
276 DEBMSG << "Starting service " << name << endmsg;
277 sc = it->sysStart();
278 if ( !sc.isSuccess() ) {
279 error() << "Unable to start Service: " << name << endmsg;
280 return sc;
281 }
282 break;
283 default:
284 error() << "Service " << name << " not in the correct state to be started (" << it->FSMState() << ")" << endmsg;
285 return StatusCode::FAILURE;
286 }
287 }
288 return StatusCode::SUCCESS;
289}
290
292 // ensure that the list is ordered by priority
293 m_listsvc.sort();
294 // we work on a copy to avoid to operate twice on the services created on demand
295 // which are already in the correct state.
296 // only act on active services
297
299 // call stop() for all services
300 for ( const auto& svc : reverse( activeSvc( m_listsvc ) ) ) {
301 const std::string& name = svc->name();
302 switch ( svc->FSMState() ) {
304 DEBMSG << "Service " << name << " already stopped" << endmsg;
305 break;
307 DEBMSG << "Stopping service " << name << endmsg;
308 sc = svc->sysStop();
309 if ( !sc.isSuccess() ) {
310 error() << "Unable to stop Service: " << name << endmsg;
311 return sc;
312 }
313 break;
314 default:
315 DEBMSG << "Service " << name << " not in the correct state to be stopped (" << svc->FSMState() << ")" << endmsg;
316 return StatusCode::FAILURE;
317 }
318 }
319 return StatusCode::SUCCESS;
320}
321
323 // ensure that the list is ordered by priority
324 m_listsvc.sort();
325 // we work on a copy to avoid to operate twice on the services created on demand
326 // which are already in the correct state.
327 // only act on active services
329 // Re-Initialize all services
330 for ( auto& svc : activeSvc( m_listsvc ) ) {
331 sc = svc->sysReinitialize();
332 if ( !sc.isSuccess() ) {
333 error() << "Unable to re-initialize Service: " << svc->name() << endmsg;
334 return StatusCode::FAILURE;
335 }
336 }
337 return StatusCode::SUCCESS;
338}
339
341 // ensure that the list is ordered by priority
342 m_listsvc.sort();
343 // we work on a copy to avoid to operate twice on the services created on demand
344 // which are already in the correct state.
345 // only act on active services
347 // Re-Start all services
348 for ( auto& svc : activeSvc( m_listsvc ) ) {
349 sc = svc->sysRestart();
350 if ( !sc.isSuccess() ) {
351 error() << "Unable to re-start Service: " << svc->name() << endmsg;
352 return StatusCode::FAILURE;
353 }
354 }
355 return StatusCode::SUCCESS;
356}
357
359 // make sure that HistogramDataSvc and THistSvc get finalized after the
360 // ToolSvc, and the FileMgr after that
361 int pri_tool = getPriority( "ToolSvc" );
362 if ( pri_tool != 0 ) {
363 setPriority( "THistSvc", pri_tool - 10 ).ignore();
364 setPriority( "ChronoStatSvc", pri_tool - 20 ).ignore();
365 setPriority( "AuditorSvc", pri_tool - 30 ).ignore();
366 setPriority( "NTupleSvc", pri_tool - 10 ).ignore();
367 setPriority( "HistogramDataSvc", pri_tool - 10 ).ignore();
368 // Preserve the relative ordering between HistogramDataSvc and HistogramPersistencySvc
369 setPriority( "HistogramPersistencySvc", pri_tool - 20 ).ignore();
370 setPriority( "HistorySvc", pri_tool - 30 ).ignore();
371 setPriority( "FileMgr", pri_tool - 40 ).ignore();
372 }
373
374 // get list of PostFinalize clients
375 std::vector<IIncidentListener*> postFinList;
376 auto p_inc = service<IIncidentSvc>( "IncidentSvc", false );
377 if ( p_inc ) {
378 p_inc->getListeners( postFinList, IncidentType::SvcPostFinalize );
379 p_inc.reset();
380 }
381
382 // ensure that the list is ordered by priority
383 m_listsvc.sort();
384 // dump();
385
387 {
388 // we work on a copy to avoid to operate twice on the services created on demand
389 // which are already in the correct state.
390 // only act on active services
391 // call finalize() for all services in reverse order
392 for ( const auto& svc : reverse( activeSvc( m_listsvc ) ) ) {
393 const std::string& name = svc->name();
394 // ignore the current state for the moment
395 // if( Gaudi::StateMachine::INITIALIZED == svc->state() )
396 DEBMSG << "Finalizing service " << name << endmsg;
397 if ( !svc->sysFinalize().isSuccess() ) {
398 warning() << "Finalization of service " << name << " failed" << endmsg;
400 }
401 }
402 }
403
404 // call SvcPostFinalize on all clients
405 if ( !postFinList.empty() ) {
406 DEBMSG << "Will call SvcPostFinalize for " << postFinList.size() << " clients" << endmsg;
407 Incident inc( "ServiceManager", IncidentType::SvcPostFinalize );
408 for ( auto& itr : postFinList ) itr->handle( inc );
409 }
410
411 // loop over all Active Services, removing them one by one.
412 // They should be deleted because the reference counting goes to 0.
413 DEBMSG << "Looping over all active services..." << endmsg;
414 auto it = m_listsvc.begin();
415 while ( it != m_listsvc.end() ) {
416 DEBMSG << "---- " << it->service->name() << " (refCount = " << it->service->refCount() << ")" << endmsg;
417 if ( it->service->refCount() < 1 ) {
418 warning() << "Too low reference count for " << it->service->name() << " (should not go below 1 at this point)"
419 << endmsg;
420 it->service->addRef();
421 }
422 if ( it->active ) {
423 it = m_listsvc.erase( it );
424 } else {
425 ++it;
426 }
427 }
428 return sc;
429}
430
431int ServiceManager::getPriority( std::string_view name ) const {
432 auto it = find( name );
433 return ( it != m_listsvc.end() ) ? it->priority : 0;
434}
435
436StatusCode ServiceManager::setPriority( std::string_view name, int prio ) {
437 auto it = find( name );
438 if ( it == m_listsvc.end() ) return StatusCode::FAILURE;
439 it->priority = prio;
440 return StatusCode::SUCCESS;
441}
442
445
447
448 auto& log = info();
449 log << "\n"
450 << "===================== listing all services ===================\n"
451 << " prior ref name active\n";
452
453 for ( const auto& svc : m_listsvc ) {
454
455 log.width( 6 );
456 log.flags( std::ios_base::right );
457 log << svc.priority << " ";
458 log.width( 5 );
459 log << svc.service->refCount() << " ";
460 log.width( 30 );
461 log.flags( std::ios_base::left );
462 log << svc.service->name() << " ";
463 log.width( 2 );
464 log << svc.active << std::endl;
465 }
466
467 log << "=================================================================\n";
468 log << endmsg;
469}
470
473 for ( auto& svcItem : m_listsvc ) {
474 const auto svc = dynamic_cast<Service*>( svcItem.service.get() );
475 if ( svc ) svc->resetMessaging();
476 }
477}
478
#define DEBMSG
bool isValidInterface(IFace *i)
Templated function that throws an exception if the version if the interface implemented by the object...
Definition IInterface.h:354
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define DECLARE_OBJECT_FACTORY(x)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
SmartIF< ISvcLocator > m_svcLocator
Service locator (needed to access the MessageSvc)
Gaudi::StateMachine::State targetFSMState() const override
When we are in the middle of a transition, get the state where the transition is leading us.
Helper class to parse a string of format "type/name".
Definition of the basic interface.
Definition IInterface.h:225
General service interface definition.
Definition IService.h:26
Base class for all Incidents (computing events).
Definition Incident.h:24
Base class for all services.
Definition Service.h:39
The ServiceManager class is in charge of the creation of concrete instances of Services.
StatusCode declareSvcType(std::string svcname, std::string svctype) override
implementation of ISvcManager::declareSvcType
const std::list< IService * > & getServices() const override
Return the list of Services.
const std::string & name() const override
Return the name of the manager (implementation of INamedInterface)
bool loopCheckEnabled() const override
Get the value of the initialization loop check flag.
StatusCode start() override
Start (from INITIALIZED to RUNNING).
void outputLevelUpdate() override
Function to call to update the outputLevel of the components (after a change in MessageSvc).
StatusCode reinitialize() override
Initialization (from INITIALIZED or RUNNING to INITIALIZED, via CONFIGURED).
StatusCode addService(IService *svc, int prio=DEFAULT_SVC_PRIORITY) override
implementation of ISvcManager::addService
StatusCode finalize() override
Finalize (from INITIALIZED to CONFIGURED).
bool existsService(std::string_view name) const override
implementation of ISvcLocation::existsService
std::list< IService * > m_listOfPtrs
List of pointers to the know services used to implement getServices()
StatusCode removeService(IService *svc) override
implementation of ISvcManager::removeService
StatusCode initialize() override
Initialization (from CONFIGURED to INITIALIZED).
StatusCode restart() override
Initialization (from RUNNING to RUNNING, via INITIALIZED).
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 > m_appSvc
Pointer to the application IService interface.
SmartIF< IService > & service(const Gaudi::Utils::TypeNameString &typeName, const bool createIf=true) override
Returns a smart pointer to a service.
~ServiceManager() override
virtual destructor
std::map< std::string, std::recursive_mutex > m_lockMap
ListSvc m_listsvc
List of service maintained by ServiceManager This contains SmartIF<T> for all services – and because ...
ServiceManager(IInterface *application)
default creator
ListSvc::iterator find(std::string_view name)
void setLoopCheckEnabled(bool en) override
Set the value of the initialization loop check flag.
bool m_loopCheck
Check for service initialization loops.
int getPriority(std::string_view name) const override
manage priorities of services
std::recursive_mutex m_gLock
Mutex to synchronize shared service initialization between threads.
StatusCode stop() override
Stop (from RUNNING to INITIALIZED).
void dump() const
StatusCode setPriority(std::string_view name, int pri) override
MapType m_maptype
Map of service name and service type.
Small smart pointer class with automatic reference counting for IInterface.
Definition SmartIF.h:28
TYPE * get() const
Get interface pointer.
Definition SmartIF.h:82
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
bool isFailure() const
Definition StatusCode.h:129
const StatusCode & ignore() const
Allow discarding a StatusCode without warning.
Definition StatusCode.h:139
bool isSuccess() const
Definition StatusCode.h:314
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
::details::reverse_wrapper< T > reverse(T &&iterable)
Definition reverse.h:58
Interface for a component that manages application configuration options.
Definition IOptionsSvc.h:46
static const InterfaceID & interfaceID()