The Gaudi Framework  master (82fdf313)
Loading...
Searching...
No Matches
ToolSvc.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#include <GaudiKernel/AlgTool.h>
18#include <GaudiKernel/Service.h>
19#include <algorithm>
20#include <boost/circular_buffer.hpp>
21#include <cassert>
22#include <functional>
23#include <map>
24#include <mutex>
25#include <numeric>
26#include <string>
27#include <vector>
28
29#define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
30#define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
31
45class ToolSvc : public extends<Service, IToolSvc> {
46
47public:
48 using extends::extends;
49
50 ~ToolSvc() override;
51
53 StatusCode finalize() override;
54
55 // Start transition for tools
56 StatusCode start() override;
57
58 // Stop transition for tools
59 StatusCode stop() override;
60
62 StatusCode retrieve( std::string_view type, const InterfaceID& iid, IAlgTool*& tool, const IInterface* parent,
63 bool createIf ) override;
64
66 StatusCode retrieve( std::string_view tooltype, std::string_view toolname, const InterfaceID& iid, IAlgTool*& tool,
67 const IInterface* parent, bool createIf ) override;
68
70 std::vector<std::string> getInstances( std::string_view toolType ) override;
71
73 std::vector<std::string> getInstances() const override;
74
76 std::vector<IAlgTool*> getTools() const override;
77
79 StatusCode releaseTool( IAlgTool* tool ) override;
80
82 StatusCode create( const std::string& type, const IInterface* parent, IAlgTool*& tool );
83
85 StatusCode create( const std::string& type, const std::string& name, const IInterface* parent, IAlgTool*& tool );
86
88 bool existsTool( std::string_view fullname ) const;
89
91 std::string nameTool( std::string_view nameByUser, const IInterface* parent );
92
93 void registerObserver( IToolSvc::Observer* obs ) override;
94
95private:
97 StatusCode finalizeTool( IAlgTool* itool ) const;
98
100 this, "CheckedNamedToolsConfigured", false,
101 "Check that tools which do not have the default name have some explicit configuration." };
102
103 Gaudi::Property<bool> m_showToolDataDeps{ this, "ShowDataDeps", false, "show the data dependencies of AlgTools" };
104
106 class ToolList {
107 std::vector<IAlgTool*> m_tools; // List of all instances of tools
108 struct Hash {
109 using is_transparent = void;
110 std::size_t operator()( IAlgTool const* s ) const noexcept { return std::hash<std::string_view>{}( s->name() ); }
111 std::size_t operator()( std::string_view s ) const noexcept { return std::hash<std::string_view>{}( s ); }
112 };
113 struct Equal {
114 using is_transparent = void;
115 bool operator()( IAlgTool const* lhs, IAlgTool const* rhs ) const { return lhs->name() == rhs->name(); }
116 bool operator()( IAlgTool const* lhs, std::string_view rhs ) const { return lhs->name() == rhs; }
117 bool operator()( std::string_view lhs, IAlgTool const* rhs ) const { return lhs == rhs->name(); }
118 };
119 std::unordered_multiset<IAlgTool*, Hash, Equal> m_map;
120
121 public:
122 void remove( IAlgTool* tool ) {
123 m_tools.erase( std::remove( std::begin( m_tools ), std::end( m_tools ), tool ), std::end( m_tools ) );
124 auto range = m_map.equal_range( tool->name() );
125 auto itm = std::find_if( range.first, range.second, [&]( auto const& p ) { return p == tool; } );
126 if ( itm != range.second ) m_map.erase( itm );
127 }
128 void push_back( IAlgTool* tool ) {
129 m_tools.push_back( tool );
130 m_map.emplace( tool );
131 }
132
133 bool contains( std::string_view name ) const { return m_map.find( name ) != m_map.end(); }
134 bool contains( IAlgTool const* tool ) const {
135 return m_tools.rend() != std::find( m_tools.rbegin(), m_tools.rend(), tool );
136 // return tool == find( tool->name(), tool->parent() ); //FIXME: is this faster?
137 }
138 auto size() const { return m_tools.size(); }
139 auto begin() const { return m_tools.begin(); }
140 auto end() const { return m_tools.end(); }
141 auto find( std::string_view name, const IInterface* parent ) const {
142 auto range = m_map.equal_range( name );
143 auto it = std::find_if( range.first, range.second, [&]( auto const& p ) { return p->parent() == parent; } );
144 return it != range.second ? *it : nullptr;
145 }
146 std::vector<IAlgTool*> grab() && {
147 m_map.clear();
148 auto tools = std::move( m_tools );
149 return tools;
150 }
151 };
152 mutable std::recursive_mutex m_mut; // protect m_instancesTools
154
157
158 std::vector<IToolSvc::Observer*> m_observers;
159};
160
161namespace {
163 template <typename C>
164 unsigned long totalRefCount( const C& toolList ) {
165 return std::accumulate( begin( toolList ), end( toolList ), 0ul,
166 [&]( unsigned long count, const IAlgTool* tool ) { return count + tool->refCount(); } );
167 }
168
170 template <typename C>
171 unsigned long minimumRefCount( const C& toolList ) {
172 return std::accumulate( begin( toolList ), end( toolList ), ~0ul,
173 []( unsigned long c, const IAlgTool* tool ) { return std::min( c, tool->refCount() ); } );
174 }
175
176} // namespace
177
179
181 // tell the remaining observers that we're gone, and forget about unregistering..
182 std::for_each( std::begin( m_observers ), std::end( m_observers ),
183 [&]( IToolSvc::Observer* obs ) { obs->setUnregister( {} ); } );
184}
185
187 // Finalize and delete all left-over tools. Normally all tools created with
188 // ToolSvc are left over, since ToolSvc holds a refCount (via AlgTool ctor).
189 // Several cases need to be covered:
190 // 1) Simple dependencies: no circular dependencies between tools,
191 // and tools not using other tools
192 // 2) Tools-using-tools (but no circular dependencies)
193 // a) release() is called in the tool::finalize() (e.g. via base class)
194 // b) release() is called in the tool destructor (e.g. via ToolHandle)
195 // 3) Circular dependencies between tools
196 // a) release() is called in the tool::finalize() (e.g. via base class)
197 // b) release() is called in the tool destructor (e.g. via ToolHandle)
198 // 4) In addition to each of the above cases, refCounting of a particular tool
199 // might not have been done correctly in the code. Typically release()
200 // is not called, so we are left with a too high refCount.
201 // What to do with those, and how to avoid a crash while handling them...
202
211 info() << "Removing all tools created by ToolSvc" << endmsg;
212 auto tools = std::move( m_instancesTools ).grab();
213
214 // Print out list of tools
215 ON_DEBUG {
216 auto& log = debug();
217 log << " Tool List : ";
218 for ( const auto& iTool : tools ) { log << iTool->name() << ":" << iTool->refCount() << " "; }
219 log << endmsg;
220 }
221
222 //
223 // first pass: Finalize all tools (but don't delete them)
224 //
237 boost::circular_buffer<IAlgTool*> finalizedTools( tools.size() ); // list of tools that have been finalized
238 bool fail( false );
239 size_t toolCount = tools.size();
240 unsigned long startRefCount = 0;
241 unsigned long endRefCount = totalRefCount( tools );
242 unsigned long startMinRefCount = 0;
243 unsigned long endMinRefCount = minimumRefCount( tools );
244 while ( toolCount > 0 && endRefCount > 0 && ( endRefCount != startRefCount || endMinRefCount != startMinRefCount ) ) {
245 ON_DEBUG if ( endMinRefCount != startMinRefCount ) {
246 debug() << toolCount << " tools left to finalize. Summed refCounts: " << endRefCount << endmsg;
247 debug() << "Will finalize tools with refCount <= " << endMinRefCount << endmsg;
248 }
249 startMinRefCount = endMinRefCount;
250 startRefCount = endRefCount;
251 unsigned long maxLoop = toolCount + 1;
252 while ( --maxLoop > 0 && !tools.empty() ) {
253 IAlgTool* pTool = tools.back();
254 // removing tool from list makes ToolSvc::releaseTool( IAlgTool* ) a noop
255 tools.pop_back();
256 unsigned long count = pTool->refCount();
257 // cache tool name
258 const std::string& toolName = pTool->name();
259 if ( count <= startMinRefCount ) {
260 ON_DEBUG debug() << " Performing finalization of " << toolName << " (refCount " << count << ")" << endmsg;
261 // finalize of one tool may trigger a release of another tool
262 // pTool->sysFinalize().ignore();
263 if ( !finalizeTool( pTool ).isSuccess() ) {
264 warning() << " FAILURE finalizing " << toolName << endmsg;
265 fail = true;
266 }
267 // postpone deletion
268 finalizedTools.push_back( pTool );
269 } else {
270 // Place back at the front of the list to try again later
271 // ToolSvc::releaseTool( IAlgTool* ) remains active for this tool
272 ON_DEBUG debug() << " Delaying finalization of " << toolName << " (refCount " << count << ")" << endmsg;
273 tools.insert( std::begin( tools ), pTool );
274 }
275 } // end of inner loop
276 toolCount = tools.size();
277 endRefCount = totalRefCount( tools );
278 endMinRefCount = minimumRefCount( tools );
279 }; // end of outer loop
280
281 //
282 // Second pass: Delete all finalized tools
283 //
284 // Delete in the order of increasing number of refCounts.
285 // Loop over tools in the same order as the order in which they were finalized.
286 // All tools in the list of finalized tools are no longer in the instancesTools list.
287 // If a tool destructor calls releaseTool() on another tool, this will have no
288 // effect on the 'other tool' if this 'other tool' is in the list of finalized tools.
289 // If this 'other tool' is still in the instancesTools list, it may trigger finalization
290 // (in releaseTool()), deletion and removal from the instancesTools list.
291 // Therefore, the check on non-finalised tools should happen *after* the deletion
292 // of the finalized tools.
293 ON_DEBUG debug() << "Deleting " << finalizedTools.size() << " finalized tools" << endmsg;
294 auto maxLoop = totalRefCount( finalizedTools ) + 1;
295 while ( --maxLoop > 0 && !finalizedTools.empty() ) {
296 IAlgTool* pTool = finalizedTools.front();
297 finalizedTools.pop_front();
298 auto count = pTool->refCount();
299 if ( count == 1 ) {
300 ON_DEBUG debug() << " Performing deletion of " << pTool->name() << endmsg;
301 } else {
302 ON_VERBOSE verbose() << " Delaying deletion of " << pTool->name() << " (refCount " << count << ")" << endmsg;
303 // Move to the end when refCount still not zero
304 finalizedTools.push_back( pTool );
305 }
306 // do a forced release
307 pTool->release();
308 }
309
310 // Error if by now not all tools are properly finalised
311 if ( !tools.empty() ) {
312 error() << "Unable to finalize and delete the following tools : ";
313 for ( const auto& iTool : tools ) { error() << iTool->name() << ": " << iTool->refCount() << " "; }
314 error() << endmsg;
315 }
316
317 // by now, all tools should be deleted and removed.
318 if ( !finalizedTools.empty() ) {
319 error() << "Failed to delete the following " << finalizedTools.size()
320 << " finalized tools. Bug in ToolSvc::finalize()?: ";
321 for ( const auto& iTool : finalizedTools ) { error() << iTool->name() << ": " << iTool->refCount() << " "; }
322 error() << endmsg;
323 }
324
325 // Finalize this specific service
326 return ( Service::finalize().isSuccess() && !fail ) ? StatusCode::SUCCESS : StatusCode::FAILURE;
327}
328
329namespace {
330 constexpr std::string_view s_PUBLIC = ":PUBLIC";
331}
332
333StatusCode ToolSvc::retrieve( std::string_view tooltype, const InterfaceID& iid, IAlgTool*& tool,
334 const IInterface* parent, bool createIf ) {
335 // check for tools, which by name are required to be public:
336 if ( tooltype.ends_with( s_PUBLIC ) ) {
337 // parent for PUBLIC tool is 'this', i.e. ToolSvc
338 tooltype.remove_suffix( s_PUBLIC.size() );
339 return retrieve( tooltype, iid, tool, this, createIf );
340 }
341
342 // protect against empty type
343 if ( tooltype.empty() ) {
344 error() << "retrieve(): No Tool Type/Name given" << endmsg;
345 return StatusCode::FAILURE;
346 }
347 auto pos = tooltype.find( '/' );
348 if ( std::string_view::npos == pos ) { return retrieve( tooltype, tooltype, iid, tool, parent, createIf ); }
349 return retrieve( tooltype.substr( 0, pos ), tooltype.substr( pos + 1 ), iid, tool, parent, createIf );
350}
351
352StatusCode ToolSvc::retrieve( std::string_view tooltype, std::string_view toolname, const InterfaceID& iid,
353 IAlgTool*& tool, const IInterface* parent, bool createIf ) {
354 // check the applicability of another method:
355 // ignore the provided name if it is empty or the type contains a name
356 if ( toolname.empty() || ( std::string_view::npos != tooltype.find( '/' ) ) ) {
357 return retrieve( tooltype, iid, tool, parent, createIf );
358 }
359
360 // check for tools, which by name are required to be public:
361 if ( toolname.ends_with( s_PUBLIC ) ) {
362 // parent for PUBLIC tool is this, i.e. ToolSvc
363 toolname.remove_suffix( s_PUBLIC.size() );
364 return retrieve( tooltype, toolname, iid, tool, this, createIf );
365 }
366
368
369 tool = nullptr;
370
371 // If parent is not specified it means it is the ToolSvc itself
372 if ( !parent ) parent = this;
373 const std::string fullname = nameTool( toolname, parent );
374
375 // Find tool in list of those already existing, and tell its
376 // interface that it has been used one more time
377 auto lock = std::scoped_lock{ m_mut };
378 IAlgTool* itool = m_instancesTools.find( fullname, parent );
379 if ( itool ) { ON_DEBUG debug() << "Retrieved tool " << toolname << " with parent " << parent << endmsg; }
380
381 if ( !itool ) {
382 // Instances of this tool do not exist, create an instance if desired
383 // otherwise return failure
384 if ( !createIf ) {
385 warning() << "Tool " << toolname << " not found and creation not requested" << endmsg;
386 return sc;
387 }
388 sc = create( std::string{ tooltype }, std::string{ toolname }, parent, itool );
389 if ( sc.isFailure() ) { return sc; }
390 }
391
392 // Get the right interface of it
393 sc = itool->queryInterface( iid, pp_cast<void>( &tool ) );
394 if ( sc.isFailure() ) {
395 error() << "Tool " << toolname << " either does not implement the correct interface, or its version is incompatible"
396 << endmsg;
397 return sc;
398 }
399
403 std::for_each( std::begin( m_observers ), std::end( m_observers ),
404 [&]( IToolSvc::Observer* obs ) { obs->onRetrieve( itool ); } );
405 return sc;
406}
407
408std::vector<std::string> ToolSvc::getInstances( std::string_view toolType ) {
409
410 std::vector<std::string> tools;
411 auto lock = std::scoped_lock{ m_mut };
412 for ( const auto& tool : m_instancesTools ) {
413 if ( tool->type() == toolType ) tools.push_back( tool->name() );
414 }
415 return tools;
416}
417
418std::vector<std::string> ToolSvc::getInstances() const {
419 auto lock = std::scoped_lock{ m_mut };
420 std::vector<std::string> tools{ m_instancesTools.size() };
421 std::transform( std::begin( m_instancesTools ), std::end( m_instancesTools ), std::begin( tools ),
422 []( const IAlgTool* t ) { return t->name(); } );
423 return tools;
424}
425
426std::vector<IAlgTool*> ToolSvc::getTools() const {
427 auto lock = std::scoped_lock{ m_mut };
428 return { std::begin( m_instancesTools ), std::end( m_instancesTools ) };
429}
430
432 auto lock = std::scoped_lock{ m_mut };
434 // test if tool is in known list (protect trying to access a previously deleted tool)
435 if ( m_instancesTools.contains( tool ) ) {
436 unsigned long count = tool->refCount();
437 if ( count == 1 ) {
438 // finalize the tool
439
441 // We are being called during ToolSvc::finalize()
442 // message format matches the one in ToolSvc::finalize()
443 debug() << " Performing finalization of " << tool->name() << " (refCount " << count << ")" << endmsg;
444 // message format matches the one in ToolSvc::finalize()
445 debug() << " Performing deletion of " << tool->name() << endmsg;
446 } else {
447 debug() << "Performing finalization and deletion of " << tool->name() << endmsg;
448 }
449 sc = finalizeTool( tool );
450 // remove from known tools...
451 m_instancesTools.remove( tool );
452 }
453 tool->release();
454 }
455 return sc;
456}
457
458StatusCode ToolSvc::create( const std::string& tooltype, const IInterface* parent, IAlgTool*& tool ) {
459 const std::string& toolname = tooltype;
460 return create( tooltype, toolname, parent, tool );
461}
462
463namespace {
466 template <typename T>
467 class ToolCreateGuard {
469 T& m_tools;
471 std::unique_ptr<IAlgTool> m_tool;
472
473 public:
474 explicit ToolCreateGuard( T& tools ) : m_tools( tools ) {}
475 // we don't get a move constructor by default because we
476 // have a non-trivial destructor... However, the default
477 // one is just fine...
478 ToolCreateGuard( ToolCreateGuard&& ) noexcept = default;
480 void create( const std::string& tooltype, const std::string& fullname, const IInterface* parent ) {
481 // remove previous content
482 if ( m_tool ) { m_tools.remove( m_tool.get() ); };
483 m_tool = AlgTool::Factory::create( tooltype, tooltype, fullname, parent );
484 // set new content
485 if ( m_tool ) { m_tools.push_back( m_tool.get() ); }
486 }
488 IAlgTool* get() { return m_tool.get(); }
489 IAlgTool* operator->() const {
490 assert( m_tool );
491 return m_tool.get();
492 }
494 IAlgTool* release() { return m_tool.release(); }
496 ~ToolCreateGuard() {
497 if ( m_tool ) m_tools.remove( m_tool.get() );
498 }
499 };
500
501 template <typename C>
502 ToolCreateGuard<C> make_toolCreateGuard( C& c ) {
503 return ToolCreateGuard<C>{ c };
504 }
505} // namespace
506
514StatusCode ToolSvc::create( const std::string& tooltype, const std::string& toolname, const IInterface* parent,
515 IAlgTool*& tool ) {
516
517 // protect against empty type
518 if ( tooltype.empty() ) {
519 error() << "create(): No Tool Type given" << endmsg;
520 return StatusCode::FAILURE;
521 }
522
523 // If parent has not been specified, assume it is the ToolSvc
524 if ( !parent ) parent = this;
525
526 tool = nullptr;
527 // Automatically deletes the tool if not explicitly kept (i.e. on success).
528 // The tool is removed from the list of known tools too.
529 auto lock = std::scoped_lock{ m_mut };
530 auto toolguard = make_toolCreateGuard( m_instancesTools );
531
532 // Check if the tool already exist : this could happen with clones
533 std::string fullname = nameTool( toolname, parent );
534 if ( existsTool( fullname ) ) {
535 // Now check if the parent is the same. This allows for clones
536 for ( IAlgTool* iAlgTool : m_instancesTools ) {
537 if ( iAlgTool->name() == toolname && iAlgTool->parent() == parent ) {
538 // The tool exist with this name, type and parent: this is bad!
539 // This excludes the possibility of cloning public tools intrinsecally
540 error() << "Tool " << fullname << " already exists with the same parent" << endmsg;
541 if ( parent == this )
542 error() << "... In addition, the parent is the ToolSvc: public tools cannot be cloned!" << endmsg;
543
544 return StatusCode::FAILURE;
545 }
546 }
547 ON_DEBUG debug() << "Creating clone of " << fullname << endmsg;
548 }
549 // instantiate the tool using the factory
550 try {
551 toolguard.create( tooltype, fullname, parent );
552 if ( !toolguard.get() ) {
553 error() << "Cannot create tool " << tooltype << " (No factory found)" << endmsg;
554 return StatusCode::FAILURE;
555 }
556 } catch ( const GaudiException& Exception ) {
557 // (1) perform the printout of message
558 fatal() << "Exception with tag=" << Exception.tag() << " is caught whilst instantiating tool '" << tooltype << "'"
559 << endmsg;
560 // (2) print the exception itself
561 // (NB! - GaudiException is a linked list of all "previous exceptions")
562 fatal() << Exception << endmsg;
563 return StatusCode::FAILURE;
564 } catch ( const std::exception& Exception ) {
565 // (1) perform the printout of message
566 fatal() << "Standard std::exception is caught whilst instantiating tool '" << tooltype << "'" << endmsg;
567 // (2) print the exception itself
568 // (NB! - GaudiException is a linked list of all "previous exceptions")
569 fatal() << Exception.what() << endmsg;
570 return StatusCode::FAILURE;
571 } catch ( ... ) {
572 // (1) perform the printout
573 fatal() << "UNKNOWN Exception is caught whilst instantiating tool '" << tooltype << "'" << endmsg;
574 return StatusCode::FAILURE;
575 }
576 ON_VERBOSE verbose() << "Created tool " << tooltype << "/" << fullname << endmsg;
577
578 // Since only AlgTool has the setProperties() method it is necessary to cast
579 // to downcast IAlgTool to AlgTool in order to set the properties via the JobOptions
580 // service
581 AlgTool* mytool = dynamic_cast<AlgTool*>( toolguard.get() );
582 if ( mytool ) mytool->bindPropertiesTo( serviceLocator()->getOptsSvc() );
583
584 // Initialize the Tool
586 try {
587 sc = toolguard->sysInitialize();
588 }
589 // Catch any exceptions
590 catch ( const GaudiException& Exception ) {
591 error() << "GaudiException with tag=" << Exception.tag() << " caught whilst initializing tool '" << fullname << "'"
592 << endmsg << Exception << endmsg;
593 return StatusCode::FAILURE;
594 } catch ( const std::exception& Exception ) {
595 error() << "Standard std::exception caught whilst initializing tool '" << fullname << "'" << endmsg
596 << Exception.what() << endmsg;
597 return StatusCode::FAILURE;
598 } catch ( ... ) {
599 error() << "UNKNOWN Exception caught whilst initializing tool '" << fullname << "'" << endmsg;
600 return StatusCode::FAILURE;
601 }
602
603 // Status of tool initialization
604 if ( sc.isFailure() ) {
605 error() << "Error initializing tool '" << fullname << "'" << endmsg;
606 return sc;
607 }
608
610 // Check to ensure that non-default named tools are configured.
611 if ( toolname != tooltype ) {
612 bool propsSet = false;
614 // Check that at least one of the properties has been set:
615 for ( const auto prop : mytool->getProperties() ) {
616 bool isSet = joSvc.isSet( mytool->name() + "." + prop->name() );
617 if ( isSet ) propsSet = true;
618 }
619 if ( !propsSet ) {
620 warning() << tooltype << "/" << fullname
621 << " : Explicitly named tools should be configured! (assigned name=" << toolname << ", default is "
622 << tooltype << ")" << endmsg;
623 }
624 }
625 }
626
627 // Start the tool if we are running.
629 sc = toolguard->sysStart();
630
631 if ( sc.isFailure() ) {
632 error() << "Error starting tool '" << fullname << "'" << endmsg;
633 return sc;
634 }
635 }
636
637 // The tool has been successfully created and initialized,
638 // so we inform the guard that it can release it
639 tool = toolguard.release();
640
644 std::for_each( m_observers.begin(), m_observers.end(), [&]( IToolSvc::Observer* obs ) { obs->onCreate( tool ); } );
645 // TODO: replace by generic callback
646 // Register the tool with the HistorySvc
647 m_pHistorySvc = service( "HistorySvc", false );
648 if ( m_pHistorySvc ) { m_pHistorySvc->registerAlgTool( *tool ).ignore(); }
649 return StatusCode::SUCCESS;
650}
651
652std::string ToolSvc::nameTool( std::string_view toolname, const IInterface* parent ) {
653
654 if ( !parent ) { return std::string{ this->name() }.append( "." ).append( toolname ); }
655
656 // check that parent has a name!
657 auto named_parent = SmartIF<INamedInterface>( const_cast<IInterface*>( parent ) );
658 if ( named_parent ) {
659 auto fullname = std::string{ named_parent->name() }.append( "." ).append( toolname );
660 return fullname;
661 }
662
663 error() << "Private Tools only allowed for components implementing INamedInterface" << endmsg;
664 //
665 return std::string{ "." }.append( toolname );
666}
667
668bool ToolSvc::existsTool( std::string_view fullname ) const {
669 auto lock = std::scoped_lock{ m_mut };
670 return m_instancesTools.contains( fullname );
671}
672
674
675 // Cache tool name in case of errors
676 const auto& toolName = itool->name();
677 StatusCode sc;
678
679 // Finalise the tool inside a try block
680 try {
681 sc = itool->sysFinalize();
682 }
683 // Catch any exceptions
684 catch ( const GaudiException& Exception ) {
685 error() << "GaudiException with tag=" << Exception.tag() << " caught whilst finalizing tool '" << toolName << "'"
686 << endmsg << Exception << endmsg;
688 } catch ( const std::exception& Exception ) {
689 error() << "Standard std::exception caught whilst finalizing tool '" << toolName << "'" << endmsg
690 << Exception.what() << endmsg;
692 } catch ( ... ) {
693 error() << "UNKNOWN Exception caught whilst finalizing tool '" << toolName << "'" << endmsg;
695 }
696
697 return sc;
698}
699
701 if ( !obs ) throw GaudiException( "Received NULL pointer", this->name() + "::registerObserver", StatusCode::FAILURE );
702
703 auto lock = std::scoped_lock{ m_mut };
704 obs->setUnregister( [this, obs]() {
705 auto lock = std::scoped_lock{ m_mut };
706 auto i = std::find( m_observers.begin(), m_observers.end(), obs );
707 if ( i != m_observers.end() ) m_observers.erase( i );
708 } );
709 m_observers.push_back( obs );
710}
711
713
714 ON_DEBUG debug() << "START transition for AlgTools" << endmsg;
715
716 if ( m_showToolDataDeps.value() ) {
717 info() << "Listing Data Dependencies of all Tools";
718 for ( auto& iTool : m_instancesTools ) {
719 IDataHandleHolder* idh = dynamic_cast<IDataHandleHolder*>( iTool );
720 if ( idh ) {
721 std::ostringstream ost;
722 for ( auto& dh : idh->inputHandles() ) { ost << "\n INPUT " << dh->fullKey(); }
723 for ( auto& id : idh->extraInputDeps() ) { ost << "\n EXTRA INPUT " << id; }
724 for ( auto& dh : idh->outputHandles() ) { ost << "\n OUTPUT " << dh->fullKey(); }
725 for ( auto& id : idh->extraOutputDeps() ) { ost << "\n EXTRA OUTPUT " << id; }
726 if ( ost.str().length() > 0 ) { info() << "\n" << iTool->name() << ost.str(); }
727 } else {
728 error() << "can't cast " << iTool->name() << " to IDataHandleHolder!" << endmsg;
729 }
730 }
731 info() << endmsg;
732 }
733
734 bool fail( false );
735 for ( auto& iTool : m_instancesTools ) {
736 ON_VERBOSE verbose() << iTool->name() << "::start()" << endmsg;
737
738 if ( !iTool->sysStart().isSuccess() ) {
739 fail = true;
740 error() << iTool->name() << " failed to start()" << endmsg;
741 }
742 }
743
744 if ( fail ) {
745 error() << "One or more AlgTools failed to start()" << endmsg;
746 return StatusCode::FAILURE;
747 }
748 return StatusCode::SUCCESS;
749}
750
752
753 ON_DEBUG debug() << "STOP transition for AlgTools" << endmsg;
754
755 bool fail( false );
756 for ( auto& iTool : m_instancesTools ) {
757 ON_VERBOSE verbose() << iTool->name() << "::stop()" << endmsg;
758
759 if ( !iTool->sysStop().isSuccess() ) {
760 fail = true;
761 error() << iTool->name() << " failed to stop()" << endmsg;
762 }
763 }
764
765 if ( fail ) {
766 error() << "One or more AlgTools failed to stop()" << endmsg;
767 return StatusCode::FAILURE;
768 }
769 return StatusCode::SUCCESS;
770}
DEST ** pp_cast(SRC **ptr)
Small function to be used instead of the construct (void**)&pointer, which produces,...
Definition IInterface.h:370
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define DECLARE_COMPONENT(type)
#define ON_VERBOSE
Definition ToolSvc.cpp:30
#define ON_DEBUG
Definition ToolSvc.cpp:29
Base class from which all the concrete tool classes should be derived.
Definition AlgTool.h:55
const std::string & name() const override
Retrieve full identifying name of the concrete tool object.
Definition AlgTool.cpp:72
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
Define general base for Gaudi exception.
The interface implemented by the AlgTool base class.
Definition IAlgTool.h:29
virtual StatusCode sysFinalize()=0
Finalization of the Tool.
virtual const DataObjIDColl & extraOutputDeps() const =0
virtual std::vector< Gaudi::DataHandle * > outputHandles() const =0
virtual std::vector< Gaudi::DataHandle * > inputHandles() const =0
virtual const DataObjIDColl & extraInputDeps() const =0
Definition of the basic interface.
Definition IInterface.h:225
virtual StatusCode queryInterface(const InterfaceID &ti, void **pp)=0
Set the void** to the pointer to the requested interface of the instance.
virtual unsigned long refCount() const =0
Current reference count.
virtual unsigned long release() const =0
Release Interface instance.
virtual const std::string & name() const =0
Retrieve the name of the instance.
Gaudi::Interfaces::IOptionsSvc & getOptsSvc()
Direct access to Gaudi::Interfaces::IOptionsSvc implementation.
allow call-backs when a tool is a created or retrieved
Definition IToolSvc.h:229
void setUnregister(std::function< void()> unregister)
Definition IToolSvc.h:234
virtual void onRetrieve(const IAlgTool *)
Definition IToolSvc.h:237
Interface ID class.
Definition IInterface.h:38
void bindPropertiesTo(Gaudi::Interfaces::IOptionsSvc &optsSvc)
const std::vector< Gaudi::Details::PropertyBase * > & getProperties() const override
get all properties
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition Service.cpp:336
StatusCode finalize() override
Definition Service.cpp:223
const std::string & name() const override
Retrieve name of the service.
Definition Service.cpp:333
Gaudi::StateMachine::State m_targetState
Service state.
Definition Service.h:157
Gaudi::StateMachine::State m_state
Service state.
Definition Service.h:155
SmartIF< IFace > service(const std::string &name, bool createIf=true) const
Definition Service.h:79
const std::vector< IAlgTool * > & tools() const
Definition Service.cpp:411
Small smart pointer class with automatic reference counting for IInterface.
Definition SmartIF.h:28
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
bool isFailure() const
Definition StatusCode.h:129
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
Common Tools.
Definition ToolSvc.cpp:106
auto end() const
Definition ToolSvc.cpp:140
auto find(std::string_view name, const IInterface *parent) const
Definition ToolSvc.cpp:141
std::vector< IAlgTool * > m_tools
Definition ToolSvc.cpp:107
auto size() const
Definition ToolSvc.cpp:138
auto begin() const
Definition ToolSvc.cpp:139
bool contains(IAlgTool const *tool) const
Definition ToolSvc.cpp:134
void push_back(IAlgTool *tool)
Definition ToolSvc.cpp:128
std::vector< IAlgTool * > grab() &&
Definition ToolSvc.cpp:146
void remove(IAlgTool *tool)
Definition ToolSvc.cpp:122
bool contains(std::string_view name) const
Definition ToolSvc.cpp:133
std::unordered_multiset< IAlgTool *, Hash, Equal > m_map
Definition ToolSvc.cpp:119
This service manages tools.
Definition ToolSvc.cpp:45
std::vector< IToolSvc::Observer * > m_observers
Definition ToolSvc.cpp:158
bool existsTool(std::string_view fullname) const
Check if the tool instance exists.
Definition ToolSvc.cpp:668
StatusCode finalizeTool(IAlgTool *itool) const
Finalize the given tool, with exception handling.
Definition ToolSvc.cpp:673
StatusCode releaseTool(IAlgTool *tool) override
Release tool.
Definition ToolSvc.cpp:431
std::vector< IAlgTool * > getTools() const override
Get pointers to all tool instances.
Definition ToolSvc.cpp:426
StatusCode create(const std::string &type, const IInterface *parent, IAlgTool *&tool)
Create Tool standard way with automatically assigned name.
Definition ToolSvc.cpp:458
StatusCode start() override
Definition ToolSvc.cpp:712
StatusCode finalize() override
Finalize the service.
Definition ToolSvc.cpp:186
void registerObserver(IToolSvc::Observer *obs) override
Definition ToolSvc.cpp:700
std::recursive_mutex m_mut
Definition ToolSvc.cpp:152
std::string nameTool(std::string_view nameByUser, const IInterface *parent)
Get Tool full name by combining nameByUser and "parent" part.
Definition ToolSvc.cpp:652
ToolList m_instancesTools
Definition ToolSvc.cpp:153
StatusCode retrieve(std::string_view type, const InterfaceID &iid, IAlgTool *&tool, const IInterface *parent, bool createIf) override
Retrieve tool, create it by default as common tool if it does not already exist.
Definition ToolSvc.cpp:333
Gaudi::Property< bool > m_showToolDataDeps
Definition ToolSvc.cpp:103
Gaudi::Property< bool > m_checkNamedToolsConfigured
Definition ToolSvc.cpp:99
SmartIF< IHistorySvc > m_pHistorySvc
Pointer to HistorySvc.
Definition ToolSvc.cpp:156
std::vector< std::string > getInstances() const override
Get names of all tool instances.
Definition ToolSvc.cpp:418
StatusCode stop() override
Definition ToolSvc.cpp:751
~ToolSvc() override
Definition ToolSvc.cpp:180
Base class used to extend a class implementing other interfaces.
Definition extends.h:19
AttribStringParser::Iterator begin(const AttribStringParser &parser)
get
decorate the vector of properties
Definition decorators.py:94
str release
Definition conf.py:27
Interface for a component that manages application configuration options.
Definition IOptionsSvc.h:46
virtual bool isSet(const std::string &key) const =0
Test if an option key was explicitly set or not.
bool operator()(IAlgTool const *lhs, IAlgTool const *rhs) const
Definition ToolSvc.cpp:115
bool operator()(std::string_view lhs, IAlgTool const *rhs) const
Definition ToolSvc.cpp:117
bool operator()(IAlgTool const *lhs, std::string_view rhs) const
Definition ToolSvc.cpp:116
std::size_t operator()(IAlgTool const *s) const noexcept
Definition ToolSvc.cpp:110
std::size_t operator()(std::string_view s) const noexcept
Definition ToolSvc.cpp:111