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