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