The Gaudi Framework  master (d98a2936)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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>
13 #include <GaudiKernel/IAlgorithm.h>
16 #include <GaudiKernel/IToolSvc.h>
17 #include <GaudiKernel/MsgStream.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 
45 class ToolSvc : public extends<Service, IToolSvc> {
46 
47 public:
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 
95 private:
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  }
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 
161 namespace {
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 
329 namespace {
330  constexpr std::string_view s_PUBLIC = ":PUBLIC";
331 }
332 
333 StatusCode 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 
352 StatusCode 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 
404  [&]( IToolSvc::Observer* obs ) { obs->onRetrieve( itool ); } );
405  return sc;
406 }
407 
408 std::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 
418 std::vector<std::string> ToolSvc::getInstances() const {
419  auto lock = std::scoped_lock{ m_mut };
420  std::vector<std::string> tools{ m_instancesTools.size() };
422  []( const IAlgTool* t ) { return t->name(); } );
423  return tools;
424 }
425 
426 std::vector<IAlgTool*> ToolSvc::getTools() const {
427  auto lock = std::scoped_lock{ m_mut };
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...
452  }
453  tool->release();
454  }
455  return sc;
456 }
457 
458 StatusCode 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 
463 namespace {
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 
514 StatusCode 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;
613  Gaudi::Interfaces::IOptionsSvc& joSvc = this->serviceLocator()->getOptsSvc();
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 
652 std::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 
668 bool 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;
687  sc = StatusCode::FAILURE;
688  } catch ( const std::exception& Exception ) {
689  error() << "Standard std::exception caught whilst finalizing tool '" << toolName << "'" << endmsg
690  << Exception.what() << endmsg;
691  sc = StatusCode::FAILURE;
692  } catch ( ... ) {
693  error() << "UNKNOWN Exception caught whilst finalizing tool '" << toolName << "'" << endmsg;
694  sc = StatusCode::FAILURE;
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 }
IDataHandleHolder
Definition: IDataHandleHolder.h:23
ToolSvc::m_observers
std::vector< IToolSvc::Observer * > m_observers
Definition: ToolSvc.cpp:158
ToolSvc::finalize
StatusCode finalize() override
Finalize the service.
Definition: ToolSvc.cpp:186
ToolSvc::m_mut
std::recursive_mutex m_mut
Definition: ToolSvc.cpp:152
ToolSvc::finalizeTool
StatusCode finalizeTool(IAlgTool *itool) const
Finalize the given tool, with exception handling.
Definition: ToolSvc.cpp:673
IAlgTool
Definition: IAlgTool.h:29
ToolSvc::m_pHistorySvc
SmartIF< IHistorySvc > m_pHistorySvc
Pointer to HistorySvc.
Definition: ToolSvc.cpp:156
ToolSvc::nameTool
std::string nameTool(std::string_view nameByUser, const IInterface *parent)
Get Tool full name by combining nameByUser and "parent" part.
Definition: ToolSvc.cpp:652
Gaudi.Configuration.log
log
Definition: Configuration.py:28
IToolSvc::Observer::setUnregister
void setUnregister(std::function< void()> unregister)
Definition: IToolSvc.h:234
IDataHandleHolder::extraInputDeps
virtual const DataObjIDColl & extraInputDeps() const =0
Service::m_state
Gaudi::StateMachine::State m_state
Service state
Definition: Service.h:155
GaudiPartProp.decorators.std
std
Definition: decorators.py:32
ToolSvc::ToolList::Hash::operator()
std::size_t operator()(std::string_view s) const noexcept
Definition: ToolSvc.cpp:111
ToolSvc::getInstances
std::vector< std::string > getInstances() const override
Get names of all tool instances.
Definition: ToolSvc.cpp:418
GaudiException.h
ToolSvc::existsTool
bool existsTool(std::string_view fullname) const
Check if the tool instance exists.
Definition: ToolSvc.cpp:668
gaudirun.s
string s
Definition: gaudirun.py:346
ToolSvc::ToolList::push_back
void push_back(IAlgTool *tool)
Definition: ToolSvc.cpp:128
ToolSvc::ToolList::Equal::operator()
bool operator()(IAlgTool const *lhs, std::string_view rhs) const
Definition: ToolSvc.cpp:116
GaudiException
Definition: GaudiException.h:29
GaudiPartProp.decorators.get
get
decorate the vector of properties
Definition: decorators.py:283
ToolSvc::ToolList::end
auto end() const
Definition: ToolSvc.cpp:140
IAlgTool::sysFinalize
virtual StatusCode sysFinalize()=0
Finalization of the Tool.
ToolSvc::ToolList::Hash::operator()
std::size_t operator()(IAlgTool const *s) const noexcept
Definition: ToolSvc.cpp:110
INamedInterface::name
virtual const std::string & name() const =0
Retrieve the name of the instance.
conf.release
string release
Definition: conf.py:27
IInterface::queryInterface
virtual StatusCode queryInterface(const InterfaceID &ti, void **pp)=0
Set the void** to the pointer to the requested interface of the instance.
gaudirun.c
c
Definition: gaudirun.py:525
Service::service
SmartIF< IFace > service(const std::string &name, bool createIf=true) const
Definition: Service.h:79
ToolSvc::getTools
std::vector< IAlgTool * > getTools() const override
Get pointers to all tool instances.
Definition: ToolSvc.cpp:426
ToolSvc
Definition: ToolSvc.cpp:45
ON_VERBOSE
#define ON_VERBOSE
Definition: ToolSvc.cpp:30
GaudiPartProp.tests.id
id
Definition: tests.py:111
ToolSvc::ToolList::begin
auto begin() const
Definition: ToolSvc.cpp:139
Service::finalize
StatusCode finalize() override
Definition: Service.cpp:223
AlgTool::name
const std::string & name() const override
Retrieve full identifying name of the concrete tool object.
Definition: AlgTool.cpp:72
ToolSvc::ToolList::contains
bool contains(std::string_view name) const
Definition: ToolSvc.cpp:133
PropertyHolder::bindPropertiesTo
void bindPropertiesTo(Gaudi::Interfaces::IOptionsSvc &optsSvc)
Definition: PropertyHolder.h:238
ToolSvc::ToolList::Equal::operator()
bool operator()(std::string_view lhs, IAlgTool const *rhs) const
Definition: ToolSvc.cpp:117
IToolSvc.h
ToolSvc::stop
StatusCode stop() override
Definition: ToolSvc.cpp:751
Service::tools
const std::vector< IAlgTool * > & tools() const
Definition: Service.cpp:411
PropertyHolder::getProperties
const std::vector< Gaudi::Details::PropertyBase * > & getProperties() const override
get all properties
Definition: PropertyHolder.h:210
ToolSvc::releaseTool
StatusCode releaseTool(IAlgTool *tool) override
Release tool.
Definition: ToolSvc.cpp:431
bug_34121.t
t
Definition: bug_34121.py:31
bug_34121.tool
tool
Definition: bug_34121.py:18
Gaudi::Utils::begin
AttribStringParser::Iterator begin(const AttribStringParser &parser)
Definition: AttribStringParser.h:135
gaudirun.default
default
Definition: gaudirun.py:188
Service::name
const std::string & name() const override
Retrieve name of the service
Definition: Service.cpp:333
StatusCode
Definition: StatusCode.h:64
Gaudi::cxx::for_each
void for_each(ContainerOfSynced &c, Fun &&f)
Definition: SynchronizedValue.h:98
ToolSvc::ToolList::Hash::is_transparent
void is_transparent
Definition: ToolSvc.cpp:109
ToolSvc::ToolList
Common Tools.
Definition: ToolSvc.cpp:106
IDataHandleHolder::extraOutputDeps
virtual const DataObjIDColl & extraOutputDeps() const =0
ToolSvc::ToolList::m_map
std::unordered_multiset< IAlgTool *, Hash, Equal > m_map
Definition: ToolSvc.cpp:119
Gaudi::StateMachine::OFFLINE
@ OFFLINE
Definition: StateMachine.h:22
ToolSvc::m_checkNamedToolsConfigured
Gaudi::Property< bool > m_checkNamedToolsConfigured
Definition: ToolSvc.cpp:99
Gaudi::Property::value
const ValueType & value() const
Definition: Property.h:229
ToolSvc::ToolList::Equal::is_transparent
void is_transparent
Definition: ToolSvc.cpp:114
ToolSvc::ToolList::Equal
Definition: ToolSvc.cpp:113
ToolSvc::ToolList::remove
void remove(IAlgTool *tool)
Definition: ToolSvc.cpp:122
SmartIF< IHistorySvc >
genconfuser.verbose
verbose
Definition: genconfuser.py:28
ToolSvc::ToolList::find
auto find(std::string_view name, const IInterface *parent) const
Definition: ToolSvc.cpp:141
ToolSvc::registerObserver
void registerObserver(IToolSvc::Observer *obs) override
Definition: ToolSvc.cpp:700
IHistorySvc.h
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:198
extends
Base class used to extend a class implementing other interfaces.
Definition: extends.h:19
IDataHandleHolder::inputHandles
virtual std::vector< Gaudi::DataHandle * > inputHandles() const =0
Gaudi::StateMachine::RUNNING
@ RUNNING
Definition: StateMachine.h:25
IToolSvc::Observer
allow call-backs when a tool is a created or retrieved
Definition: IToolSvc.h:229
ToolSvc::ToolList::contains
bool contains(IAlgTool const *tool) const
Definition: ToolSvc.cpp:134
Service.h
ToolSvc::create
StatusCode create(const std::string &type, const IInterface *parent, IAlgTool *&tool)
Create Tool standard way with automatically assigned name.
Definition: ToolSvc.cpp:458
StatusCode::isFailure
bool isFailure() const
Definition: StatusCode.h:129
gaudirun.type
type
Definition: gaudirun.py:160
ToolSvc::retrieve
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
IToolSvc::Observer::onRetrieve
virtual void onRetrieve(const IAlgTool *)
Definition: IToolSvc.h:237
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:99
gaudirun.toolname
toolname
Definition: gaudirun.py:454
ToolSvc::ToolList::size
auto size() const
Definition: ToolSvc.cpp:138
AlgTool
Definition: AlgTool.h:55
ToolSvc::ToolList::Hash
Definition: ToolSvc.cpp:108
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:45
IInterface
Definition: IInterface.h:225
ToolSvc::ToolList::Equal::operator()
bool operator()(IAlgTool const *lhs, IAlgTool const *rhs) const
Definition: ToolSvc.cpp:115
IDataHandleHolder::outputHandles
virtual std::vector< Gaudi::DataHandle * > outputHandles() const =0
ToolSvc::ToolList::grab
std::vector< IAlgTool * > grab() &&
Definition: ToolSvc.cpp:146
Service::m_targetState
Gaudi::StateMachine::State m_targetState
Service state
Definition: Service.h:157
AlgTool.h
ON_DEBUG
#define ON_DEBUG
Definition: ToolSvc.cpp:29
ToolSvc::start
StatusCode start() override
Definition: ToolSvc.cpp:712
InterfaceID
Definition: IInterface.h:38
IOTest.end
end
Definition: IOTest.py:125
IAlgorithm.h
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:100
IInterface::refCount
virtual unsigned long refCount() const =0
Current reference count.
ISvcLocator.h
ToolSvc::m_instancesTools
ToolList m_instancesTools
Definition: ToolSvc.cpp:153
Gaudi::Interfaces::IOptionsSvc
Interface for a component that manages application configuration options.
Definition: IOptionsSvc.h:46
Gaudi::Accumulators::accumulate
void accumulate(Counter &counter, const Container &container, Fun f=Identity{})
A helper function for accumulating data from a container into a counter This is internally using buff...
Definition: Accumulators.h:1227
ToolSvc::m_showToolDataDeps
Gaudi::Property< bool > m_showToolDataDeps
Definition: ToolSvc.cpp:103
ToolSvc::ToolList::m_tools
std::vector< IAlgTool * > m_tools
Definition: ToolSvc.cpp:107
Gaudi::Property< bool >
ToolSvc::~ToolSvc
~ToolSvc() override
Definition: ToolSvc.cpp:180
IInterface::release
virtual unsigned long release() const =0
Release Interface instance.
MsgStream.h
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: details.h:86
Service::serviceLocator
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator
Definition: Service.cpp:336
Gaudi::Interfaces::IOptionsSvc::isSet
virtual bool isSet(const std::string &key) const =0
Test if an option key was explicitly set or not.