The Gaudi Framework  master (76629ece)
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 // FIXME: we used to have an invocation of isValidInterface, which implied an addRef() call
89 // now that isValidInterface has been deprecated, I added a call to addRef(), but I'm not
90 // sure if this is the right thing to do.
91 service->addRef();
92
93 if ( name == "JobOptionsSvc" ) {
94 if ( !dynamic_cast<Gaudi::Interfaces::IOptionsSvc*>( service ) ) {
95 fatal() << typeName << " does not implement Gaudi::Interfaces::IOptionsSvc" << endmsg;
96 return no_service;
97 }
98 }
99
100 auto lck = std::scoped_lock{ m_gLock };
101 m_listsvc.push_back( service );
102 service->setServiceManager( this );
103 return m_listsvc.back().service; // DANGER: returns a reference to a SmartIF in m_listsvc, and hence does no longer
104 // allow relocations of those...
105}
106
108 auto it = find( svc );
109 auto lck = std::scoped_lock{ m_gLock };
110 if ( it != m_listsvc.end() ) {
111 it->priority = prio; // if the service is already known, it is equivalent to a setPriority
112 it->active = true; // and make it active
113 } else {
114 m_listsvc.emplace_back( svc, prio, true );
115 }
116 return StatusCode::SUCCESS;
117}
118
120 auto it = find( typeName.name() ); // try to find the service by name
121 if ( it == m_listsvc.end() ) { // not found
122 // If the service does not exist, we create it
123 SmartIF<IService>& svc =
124 createService( typeName ); // WARNING: svc is now a reference to something that lives in m_listsvc
125 if ( !svc ) return StatusCode::FAILURE;
126 it = find( svc.get() ); // now it is in the list because createService added it
127 it->priority = prio;
129 if ( targetFSMState() >= Gaudi::StateMachine::INITIALIZED ) { // WARNING: this can trigger a recursion!!!
130 sc = svc->sysInitialize();
131 if ( sc.isSuccess() && targetFSMState() >= Gaudi::StateMachine::RUNNING ) { sc = svc->sysStart(); }
132 }
133 if ( sc.isFailure() ) { // if initialization failed, remove it from the list
134 error() << "Unable to initialize service \"" << typeName.name() << "\"" << endmsg;
135 auto lck = std::scoped_lock{ m_gLock };
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 }
141 // initialization successful, we can work with the service
142 // Move the just initialized service to the back of the list
143 // (we care more about order of initialization than of creation)
144 auto lck = std::scoped_lock{ m_gLock };
145 m_listsvc.push_back( *it );
146 m_listsvc.erase( it );
147 it = std::prev( std::end( m_listsvc ) ); // last entry (the iterator was invalidated by erase)
148 } else {
149 // if the service is already known, it is equivalent to a setPriority
150 it->priority = prio;
151 }
152 // 'it' is defined because either we found the service or we created it
153 // Now we can activate the service
154 it->active = true; // and make it active
155 return StatusCode::SUCCESS;
156}
157
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
163 auto* imut = [&] {
164 // get the global lock, then extract/create the service specific mutex
165 // then release global lock
166
167 auto lk = std::scoped_lock{ this->m_gLock };
168 auto mit = m_lockMap.find( name );
169 if ( mit == m_lockMap.end() ) {
170 mit = m_lockMap.emplace( std::piecewise_construct_t{}, std::forward_as_tuple( name ), std::forward_as_tuple() )
171 .first;
172 }
173 return &mit->second;
174 }();
175
176 {
177 // now we have the service specific lock on the above mutex
178 auto lk2 = std::scoped_lock{ *imut };
179
180 auto it = find( name );
181
182 if ( it != m_listsvc.end() ) {
183 if ( m_loopCheck && ( createIf && it->service->FSMState() == Gaudi::StateMachine::CONFIGURED ) ) {
184 error() << "Initialization loop detected when creating service \"" << name << "\"" << endmsg;
185 return no_service;
186 }
187 return it->service;
188 }
189
190 // Service not found. The user may be interested in one of the interfaces
191 // of the application manager itself
192 if ( name == "ApplicationMgr" || name == "APPMGR" || name == "" ) { return m_appSvc; }
193
194 // last resort: we try to create the service
195 if ( createIf && addService( typeName ).isSuccess() ) { return find( name )->service; }
196
197 return no_service;
198 }
199}
200
201const std::list<IService*>& ServiceManager::getServices() const {
202 m_listOfPtrs.clear();
203 std::transform( std::begin( m_listsvc ), std::end( m_listsvc ), std::back_inserter( m_listOfPtrs ),
204 []( ListSvc::const_reference i ) { return i.service.get(); } );
205 return m_listOfPtrs;
206}
207
208bool ServiceManager::existsService( std::string_view name ) const { return find( name ) != m_listsvc.end(); }
209
211 auto it = find( svc );
212 if ( it == m_listsvc.end() ) return StatusCode::FAILURE;
213 m_listsvc.erase( it );
214 return StatusCode::SUCCESS;
215}
216
218 auto it = find( name );
219 if ( it == m_listsvc.end() ) return StatusCode::FAILURE;
220 m_listsvc.erase( it );
221 return StatusCode::SUCCESS;
222}
223
224StatusCode ServiceManager::declareSvcType( std::string svcname, std::string svctype ) {
225 m_maptype.insert_or_assign( std::move( svcname ), std::move( svctype ) );
226 return StatusCode::SUCCESS;
227}
228
230 // ensure that the list is ordered by priority
231 m_listsvc.sort();
232 // we work on a copy to avoid to operate twice on the services created on demand
233 // which are already in the correct state.
234
236 // call initialize() for all services
237 for ( auto& it : activeSvc( m_listsvc ) ) {
238 const std::string& name = it->name();
239 switch ( it->FSMState() ) {
241 DEBMSG << "Service " << name << " already initialized" << endmsg;
242 break;
244 DEBMSG << "Initializing service " << name << endmsg;
245 sc = it->sysInitialize();
246 if ( !sc.isSuccess() ) {
247 error() << "Unable to initialize Service: " << name << endmsg;
248 return sc;
249 }
250 break;
251 default:
252 error() << "Service " << name << " not in the correct state to be initialized (" << it->FSMState() << ")"
253 << endmsg;
254 return StatusCode::FAILURE;
255 }
256 }
257 return StatusCode::SUCCESS;
258}
259
261 // ensure that the list is ordered by priority
262 m_listsvc.sort();
263 // we work on a copy to avoid to operate twice on the services created on demand
264 // (which are already in the correct state.
265 // only act on active services
267 // call initialize() for all services
268 for ( auto& it : activeSvc( m_listsvc ) ) {
269 const std::string& name = it->name();
270 switch ( it->FSMState() ) {
272 DEBMSG << "Service " << name << " already started" << endmsg;
273 break;
275 DEBMSG << "Starting service " << name << endmsg;
276 sc = it->sysStart();
277 if ( !sc.isSuccess() ) {
278 error() << "Unable to start Service: " << name << endmsg;
279 return sc;
280 }
281 break;
282 default:
283 error() << "Service " << name << " not in the correct state to be started (" << it->FSMState() << ")" << endmsg;
284 return StatusCode::FAILURE;
285 }
286 }
287 return StatusCode::SUCCESS;
288}
289
291 // ensure that the list is ordered by priority
292 m_listsvc.sort();
293 // we work on a copy to avoid to operate twice on the services created on demand
294 // which are already in the correct state.
295 // only act on active services
296
298 // call stop() for all services
299 for ( const auto& svc : reverse( activeSvc( m_listsvc ) ) ) {
300 const std::string& name = svc->name();
301 switch ( svc->FSMState() ) {
303 DEBMSG << "Service " << name << " already stopped" << endmsg;
304 break;
306 DEBMSG << "Stopping service " << name << endmsg;
307 sc = svc->sysStop();
308 if ( !sc.isSuccess() ) {
309 error() << "Unable to stop Service: " << name << endmsg;
310 return sc;
311 }
312 break;
313 default:
314 DEBMSG << "Service " << name << " not in the correct state to be stopped (" << svc->FSMState() << ")" << endmsg;
315 return StatusCode::FAILURE;
316 }
317 }
318 return StatusCode::SUCCESS;
319}
320
322 // ensure that the list is ordered by priority
323 m_listsvc.sort();
324 // we work on a copy to avoid to operate twice on the services created on demand
325 // which are already in the correct state.
326 // only act on active services
328 // Re-Initialize all services
329 for ( auto& svc : activeSvc( m_listsvc ) ) {
330 sc = svc->sysReinitialize();
331 if ( !sc.isSuccess() ) {
332 error() << "Unable to re-initialize Service: " << svc->name() << endmsg;
333 return StatusCode::FAILURE;
334 }
335 }
336 return StatusCode::SUCCESS;
337}
338
340 // ensure that the list is ordered by priority
341 m_listsvc.sort();
342 // we work on a copy to avoid to operate twice on the services created on demand
343 // which are already in the correct state.
344 // only act on active services
346 // Re-Start all services
347 for ( auto& svc : activeSvc( m_listsvc ) ) {
348 sc = svc->sysRestart();
349 if ( !sc.isSuccess() ) {
350 error() << "Unable to re-start Service: " << svc->name() << endmsg;
351 return StatusCode::FAILURE;
352 }
353 }
354 return StatusCode::SUCCESS;
355}
356
358 // make sure that HistogramDataSvc and THistSvc get finalized after the
359 // ToolSvc, and the FileMgr after that
360 int pri_tool = getPriority( "ToolSvc" );
361 if ( pri_tool != 0 ) {
362 setPriority( "THistSvc", pri_tool - 10 ).ignore();
363 setPriority( "ChronoStatSvc", pri_tool - 20 ).ignore();
364 setPriority( "AuditorSvc", pri_tool - 30 ).ignore();
365 setPriority( "NTupleSvc", pri_tool - 10 ).ignore();
366 setPriority( "HistogramDataSvc", pri_tool - 10 ).ignore();
367 // Preserve the relative ordering between HistogramDataSvc and HistogramPersistencySvc
368 setPriority( "HistogramPersistencySvc", pri_tool - 20 ).ignore();
369 setPriority( "HistorySvc", pri_tool - 30 ).ignore();
370 setPriority( "FileMgr", pri_tool - 40 ).ignore();
371 }
372
373 // get list of PostFinalize clients
374 std::vector<IIncidentListener*> postFinList;
375 auto p_inc = service<IIncidentSvc>( "IncidentSvc", false );
376 if ( p_inc ) {
377 p_inc->getListeners( postFinList, IncidentType::SvcPostFinalize );
378 p_inc.reset();
379 }
380
381 // ensure that the list is ordered by priority
382 m_listsvc.sort();
383 // dump();
384
386 {
387 // we work on a copy to avoid to operate twice on the services created on demand
388 // which are already in the correct state.
389 // only act on active services
390 // call finalize() for all services in reverse order
391 for ( const auto& svc : reverse( activeSvc( m_listsvc ) ) ) {
392 const std::string& name = svc->name();
393 // ignore the current state for the moment
394 // if( Gaudi::StateMachine::INITIALIZED == svc->state() )
395 DEBMSG << "Finalizing service " << name << endmsg;
396 if ( !svc->sysFinalize().isSuccess() ) {
397 warning() << "Finalization of service " << name << " failed" << endmsg;
399 }
400 }
401 }
402
403 // call SvcPostFinalize on all clients
404 if ( !postFinList.empty() ) {
405 DEBMSG << "Will call SvcPostFinalize for " << postFinList.size() << " clients" << endmsg;
406 Incident inc( "ServiceManager", IncidentType::SvcPostFinalize );
407 for ( auto& itr : postFinList ) itr->handle( inc );
408 }
409
410 // loop over all Active Services, removing them one by one.
411 // They should be deleted because the reference counting goes to 0.
412 DEBMSG << "Looping over all active services..." << endmsg;
413 auto it = m_listsvc.begin();
414 while ( it != m_listsvc.end() ) {
415 DEBMSG << "---- " << it->service->name() << " (refCount = " << it->service->refCount() << ")" << endmsg;
416 if ( it->service->refCount() < 1 ) {
417 warning() << "Too low reference count for " << it->service->name() << " (should not go below 1 at this point)"
418 << endmsg;
419 it->service->addRef();
420 }
421 if ( it->active ) {
422 it = m_listsvc.erase( it );
423 } else {
424 ++it;
425 }
426 }
427 return sc;
428}
429
430int ServiceManager::getPriority( std::string_view name ) const {
431 auto it = find( name );
432 return ( it != m_listsvc.end() ) ? it->priority : 0;
433}
434
435StatusCode ServiceManager::setPriority( std::string_view name, int prio ) {
436 auto it = find( name );
437 if ( it == m_listsvc.end() ) return StatusCode::FAILURE;
438 it->priority = prio;
439 return StatusCode::SUCCESS;
440}
441
444
446
447 auto& log = info();
448 log << "\n"
449 << "===================== listing all services ===================\n"
450 << " prior ref name active\n";
451
452 for ( const auto& svc : m_listsvc ) {
453
454 log.width( 6 );
455 log.flags( std::ios_base::right );
456 log << svc.priority << " ";
457 log.width( 5 );
458 log << svc.service->refCount() << " ";
459 log.width( 30 );
460 log.flags( std::ios_base::left );
461 log << svc.service->name() << " ";
462 log.width( 2 );
463 log << svc.active << std::endl;
464 }
465
466 log << "=================================================================\n";
467 log << endmsg;
468}
469
472 for ( auto& svcItem : m_listsvc ) {
473 const auto svc = dynamic_cast<Service*>( svcItem.service.get() );
474 if ( svc ) svc->resetMessaging();
475 }
476}
477
#define DEBMSG
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()