The Gaudi Framework  v39r0 (5b8b5eda)
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  if ( m_pHistorySvc ) m_pHistorySvc->release();
356 
357  // Finalize this specific service
358  return ( Service::finalize().isSuccess() && !fail ) ? StatusCode::SUCCESS : StatusCode::FAILURE;
359 }
360 
361 // ===================================================================================
365 // ===================================================================================
366 namespace {
367  static const std::string s_PUBLIC = ":PUBLIC";
368 }
369 
370 //------------------------------------------------------------------------------
371 StatusCode ToolSvc::retrieve( std::string_view tooltype, const InterfaceID& iid, IAlgTool*& tool,
372  const IInterface* parent, bool createIf )
373 //------------------------------------------------------------------------------
374 {
375  // check for tools, which by name are required to be public:
376  if ( ba::ends_with( tooltype, s_PUBLIC ) ) {
377  // parent for PUBLIC tool is 'this', i.e. ToolSvc
378  tooltype.remove_suffix( s_PUBLIC.size() );
379  return retrieve( tooltype, iid, tool, this, createIf );
380  }
381 
382  // protect against empty type
383  if ( tooltype.empty() ) {
384  error() << "retrieve(): No Tool Type/Name given" << endmsg;
385  return StatusCode::FAILURE;
386  }
387  auto pos = tooltype.find( '/' );
388  if ( std::string_view::npos == pos ) { return retrieve( tooltype, tooltype, iid, tool, parent, createIf ); }
389  return retrieve( tooltype.substr( 0, pos ), tooltype.substr( pos + 1 ), iid, tool, parent, createIf );
390 }
391 
392 // ===================================================================================
393 
394 //------------------------------------------------------------------------------
395 StatusCode ToolSvc::retrieve( std::string_view tooltype, std::string_view toolname, const InterfaceID& iid,
396  IAlgTool*& tool, const IInterface* parent, bool createIf )
397 //------------------------------------------------------------------------------
398 {
399  // check the applicability of another method:
400  // ignore the provided name if it is empty or the type contains a name
401  if ( toolname.empty() || ( std::string_view::npos != tooltype.find( '/' ) ) ) {
402  return retrieve( tooltype, iid, tool, parent, createIf );
403  }
404 
405  // check for tools, which by name are required to be public:
406  if ( ba::ends_with( toolname, s_PUBLIC ) ) {
407  // parent for PUBLIC tool is this, i.e. ToolSvc
408  toolname.remove_suffix( s_PUBLIC.size() );
409  return retrieve( tooltype, toolname, iid, tool, this, createIf );
410  }
411 
413 
414  tool = nullptr;
415 
416  // If parent is not specified it means it is the ToolSvc itself
417  if ( !parent ) parent = this;
418  const std::string fullname = nameTool( toolname, parent );
419 
420  // Find tool in list of those already existing, and tell its
421  // interface that it has been used one more time
422  auto lock = std::scoped_lock{ m_mut };
423  IAlgTool* itool = m_instancesTools.find( fullname, parent );
424  if ( itool ) { ON_DEBUG debug() << "Retrieved tool " << toolname << " with parent " << parent << endmsg; }
425 
426  if ( !itool ) {
427  // Instances of this tool do not exist, create an instance if desired
428  // otherwise return failure
429  if ( !createIf ) {
430  warning() << "Tool " << toolname << " not found and creation not requested" << endmsg;
431  return sc;
432  }
433  sc = create( std::string{ tooltype }, std::string{ toolname }, parent, itool );
434  if ( sc.isFailure() ) { return sc; }
435  }
436 
437  // Get the right interface of it
438  sc = itool->queryInterface( iid, pp_cast<void>( &tool ) );
439  if ( sc.isFailure() ) {
440  error() << "Tool " << toolname << " either does not implement the correct interface, or its version is incompatible"
441  << endmsg;
442  return sc;
443  }
444 
449  [&]( IToolSvc::Observer* obs ) { obs->onRetrieve( itool ); } );
450  return sc;
451 }
452 //------------------------------------------------------------------------------
454 //------------------------------------------------------------------------------
455 {
456 
458  auto lock = std::scoped_lock{ m_mut };
459  for ( const auto& tool : m_instancesTools ) {
460  if ( tool->type() == toolType ) tools.push_back( tool->name() );
461  }
462  return tools;
463 }
464 //------------------------------------------------------------------------------
466 //------------------------------------------------------------------------------
467 {
468  auto lock = std::scoped_lock{ m_mut };
471  []( const IAlgTool* t ) { return t->name(); } );
472  return tools;
473 }
474 //------------------------------------------------------------------------------
476 //------------------------------------------------------------------------------
477 {
478  auto lock = std::scoped_lock{ m_mut };
480 }
481 //------------------------------------------------------------------------------
483 //------------------------------------------------------------------------------
484 {
485  auto lock = std::scoped_lock{ m_mut };
487  // test if tool is in known list (protect trying to access a previously deleted tool)
488  if ( m_instancesTools.contains( tool ) ) {
489  unsigned long count = tool->refCount();
490  if ( count == 1 ) {
491  // finalize the tool
492 
494  // We are being called during ToolSvc::finalize()
495  // message format matches the one in ToolSvc::finalize()
496  debug() << " Performing finalization of " << tool->name() << " (refCount " << count << ")" << endmsg;
497  // message format matches the one in ToolSvc::finalize()
498  debug() << " Performing deletion of " << tool->name() << endmsg;
499  } else {
500  debug() << "Performing finalization and deletion of " << tool->name() << endmsg;
501  }
502  sc = finalizeTool( tool );
503  // remove from known tools...
505  }
506  tool->release();
507  }
508  return sc;
509 }
510 
511 //------------------------------------------------------------------------------
512 StatusCode ToolSvc::create( const std::string& tooltype, const IInterface* parent, IAlgTool*& tool )
513 //------------------------------------------------------------------------------
514 {
515  const std::string& toolname = tooltype;
516  return create( tooltype, toolname, parent, tool );
517 }
518 
519 namespace {
522  template <typename T>
523  class ToolCreateGuard {
525  T& m_tools;
528 
529  public:
530  explicit ToolCreateGuard( T& tools ) : m_tools( tools ) {}
531  // we don't get a move constructor by default because we
532  // have a non-trivial destructor... However, the default
533  // one is just fine...
534  ToolCreateGuard( ToolCreateGuard&& ) noexcept = default;
536  void create( const std::string& tooltype, const std::string& fullname, const IInterface* parent ) {
537  // remove previous content
538  if ( m_tool ) { m_tools.remove( m_tool.get() ); };
539  m_tool = AlgTool::Factory::create( tooltype, tooltype, fullname, parent );
540  // set new content
541  if ( m_tool ) { m_tools.push_back( m_tool.get() ); }
542  }
544  IAlgTool* get() { return m_tool.get(); }
545  IAlgTool* operator->() const {
546  assert( m_tool );
547  return m_tool.get();
548  }
550  IAlgTool* release() { return m_tool.release(); }
552  ~ToolCreateGuard() {
553  if ( m_tool ) m_tools.remove( m_tool.get() );
554  }
555  };
556 
557  template <typename C>
558  ToolCreateGuard<C> make_toolCreateGuard( C& c ) {
559  return ToolCreateGuard<C>{ c };
560  }
561 } // namespace
562 
563 //------------------------------------------------------------------------------
571 StatusCode ToolSvc::create( const std::string& tooltype, const std::string& toolname, const IInterface* parent,
572  IAlgTool*& tool )
573 //------------------------------------------------------------------------------
574 {
575 
576  // protect against empty type
577  if ( tooltype.empty() ) {
578  error() << "create(): No Tool Type given" << endmsg;
579  return StatusCode::FAILURE;
580  }
581 
582  // If parent has not been specified, assume it is the ToolSvc
583  if ( !parent ) parent = this;
584 
585  tool = nullptr;
586  // Automatically deletes the tool if not explicitly kept (i.e. on success).
587  // The tool is removed from the list of known tools too.
588  auto lock = std::scoped_lock{ m_mut };
589  auto toolguard = make_toolCreateGuard( m_instancesTools );
590 
591  // Check if the tool already exist : this could happen with clones
592  std::string fullname = nameTool( toolname, parent );
593  if ( existsTool( fullname ) ) {
594  // Now check if the parent is the same. This allows for clones
595  for ( IAlgTool* iAlgTool : m_instancesTools ) {
596  if ( iAlgTool->name() == toolname && iAlgTool->parent() == parent ) {
597  // The tool exist with this name, type and parent: this is bad!
598  // This excludes the possibility of cloning public tools intrinsecally
599  error() << "Tool " << fullname << " already exists with the same parent" << endmsg;
600  if ( parent == this )
601  error() << "... In addition, the parent is the ToolSvc: public tools cannot be cloned!" << endmsg;
602 
603  return StatusCode::FAILURE;
604  }
605  }
606  ON_DEBUG debug() << "Creating clone of " << fullname << endmsg;
607  }
608  // instantiate the tool using the factory
609  try {
610  toolguard.create( tooltype, fullname, parent );
611  if ( !toolguard.get() ) {
612  error() << "Cannot create tool " << tooltype << " (No factory found)" << endmsg;
613  return StatusCode::FAILURE;
614  }
615  } catch ( const GaudiException& Exception ) {
616  // (1) perform the printout of message
617  fatal() << "Exception with tag=" << Exception.tag() << " is caught whilst instantiating tool '" << tooltype << "'"
618  << endmsg;
619  // (2) print the exception itself
620  // (NB! - GaudiException is a linked list of all "previous exceptions")
621  fatal() << Exception << endmsg;
622  return StatusCode::FAILURE;
623  } catch ( const std::exception& Exception ) {
624  // (1) perform the printout of message
625  fatal() << "Standard std::exception is caught whilst instantiating tool '" << tooltype << "'" << endmsg;
626  // (2) print the exception itself
627  // (NB! - GaudiException is a linked list of all "previous exceptions")
628  fatal() << Exception.what() << endmsg;
629  return StatusCode::FAILURE;
630  } catch ( ... ) {
631  // (1) perform the printout
632  fatal() << "UNKNOWN Exception is caught whilst instantiating tool '" << tooltype << "'" << endmsg;
633  return StatusCode::FAILURE;
634  }
635  ON_VERBOSE verbose() << "Created tool " << tooltype << "/" << fullname << endmsg;
636 
637  // Since only AlgTool has the setProperties() method it is necessary to cast
638  // to downcast IAlgTool to AlgTool in order to set the properties via the JobOptions
639  // service
640  AlgTool* mytool = dynamic_cast<AlgTool*>( toolguard.get() );
641  if ( mytool ) mytool->bindPropertiesTo( serviceLocator()->getOptsSvc() );
642 
643  // Initialize the Tool
645  try {
646  sc = toolguard->sysInitialize();
647  }
648  // Catch any exceptions
649  catch ( const GaudiException& Exception ) {
650  error() << "GaudiException with tag=" << Exception.tag() << " caught whilst initializing tool '" << fullname << "'"
651  << endmsg << Exception << endmsg;
652  return StatusCode::FAILURE;
653  } catch ( const std::exception& Exception ) {
654  error() << "Standard std::exception caught whilst initializing tool '" << fullname << "'" << endmsg
655  << Exception.what() << endmsg;
656  return StatusCode::FAILURE;
657  } catch ( ... ) {
658  error() << "UNKNOWN Exception caught whilst initializing tool '" << fullname << "'" << endmsg;
659  return StatusCode::FAILURE;
660  }
661 
662  // Status of tool initialization
663  if ( sc.isFailure() ) {
664  error() << "Error initializing tool '" << fullname << "'" << endmsg;
665  return sc;
666  }
667 
669  // Check to ensure that non-default named tools are configured.
670  if ( toolname != tooltype ) {
671  bool propsSet = false;
672  Gaudi::Interfaces::IOptionsSvc& joSvc = this->serviceLocator()->getOptsSvc();
673  // Check that at least one of the properties has been set:
674  for ( const auto prop : mytool->getProperties() ) {
675  bool isSet = joSvc.isSet( mytool->name() + "." + prop->name() );
676  if ( isSet ) propsSet = true;
677  }
678  if ( !propsSet ) {
679  warning() << tooltype << "/" << fullname
680  << " : Explicitly named tools should be configured! (assigned name=" << toolname << ", default is "
681  << tooltype << ")" << endmsg;
682  }
683  }
684  }
685 
686  // Start the tool if we are running.
688  sc = toolguard->sysStart();
689 
690  if ( sc.isFailure() ) {
691  error() << "Error starting tool '" << fullname << "'" << endmsg;
692  return sc;
693  }
694  }
695 
696  // The tool has been successfully created and initialized,
697  // so we inform the guard that it can release it
698  tool = toolguard.release();
699 
703  std::for_each( m_observers.begin(), m_observers.end(), [&]( IToolSvc::Observer* obs ) { obs->onCreate( tool ); } );
704  // TODO: replace by generic callback
705  // Register the tool with the HistorySvc
706  if ( m_pHistorySvc || service( "HistorySvc", m_pHistorySvc, false ).isSuccess() ) {
708  }
709  return StatusCode::SUCCESS;
710 }
711 
712 //------------------------------------------------------------------------------
713 std::string ToolSvc::nameTool( std::string_view toolname, const IInterface* parent )
714 //------------------------------------------------------------------------------
715 {
716 
717  if ( !parent ) { return std::string{ this->name() }.append( "." ).append( toolname ); } // RETURN
718 
719  // check that parent has a name!
720  auto named_parent = SmartIF<INamedInterface>( const_cast<IInterface*>( parent ) );
721  if ( named_parent ) {
722  auto fullname = std::string{ named_parent->name() }.append( "." ).append( toolname );
723  return fullname; // RETURN
724  }
725 
726  error() << "Private Tools only allowed for components implementing INamedInterface" << endmsg;
727  //
728  return std::string{ "." }.append( toolname );
729 }
730 
731 //------------------------------------------------------------------------------
732 bool ToolSvc::existsTool( std::string_view fullname ) const
733 //------------------------------------------------------------------------------
734 {
735  auto lock = std::scoped_lock{ m_mut };
736  return m_instancesTools.contains( fullname );
737 }
738 
739 //------------------------------------------------------------------------------
741 //------------------------------------------------------------------------------
742 {
743 
744  // Cache tool name in case of errors
745  const auto& toolName = itool->name();
746  StatusCode sc;
747 
748  // Finalise the tool inside a try block
749  try {
750  sc = itool->sysFinalize();
751  }
752  // Catch any exceptions
753  catch ( const GaudiException& Exception ) {
754  error() << "GaudiException with tag=" << Exception.tag() << " caught whilst finalizing tool '" << toolName << "'"
755  << endmsg << Exception << endmsg;
756  sc = StatusCode::FAILURE;
757  } catch ( const std::exception& Exception ) {
758  error() << "Standard std::exception caught whilst finalizing tool '" << toolName << "'" << endmsg
759  << Exception.what() << endmsg;
760  sc = StatusCode::FAILURE;
761  } catch ( ... ) {
762  error() << "UNKNOWN Exception caught whilst finalizing tool '" << toolName << "'" << endmsg;
763  sc = StatusCode::FAILURE;
764  }
765 
766  return sc;
767 }
768 
769 //------------------------------------------------------------------------------
771  //------------------------------------------------------------------------------
772  if ( !obs ) throw GaudiException( "Received NULL pointer", this->name() + "::registerObserver", StatusCode::FAILURE );
773 
774  auto lock = std::scoped_lock{ m_mut };
775  obs->setUnregister( [this, obs]() {
776  auto lock = std::scoped_lock{ m_mut };
777  auto i = std::find( m_observers.begin(), m_observers.end(), obs );
778  if ( i != m_observers.end() ) m_observers.erase( i );
779  } );
780  m_observers.push_back( obs );
781 }
782 
783 //------------------------------------------------------------------------------
785 //------------------------------------------------------------------------------
786 {
787 
788  ON_DEBUG debug() << "START transition for AlgTools" << endmsg;
789 
790  if ( m_showToolDataDeps.value() ) {
791  info() << "Listing Data Dependencies of all Tools";
792  for ( auto& iTool : m_instancesTools ) {
793  IDataHandleHolder* idh = dynamic_cast<IDataHandleHolder*>( iTool );
794  if ( idh ) {
795  std::ostringstream ost;
796  for ( auto& dh : idh->inputHandles() ) { ost << "\n INPUT " << dh->fullKey(); }
797  for ( auto& id : idh->extraInputDeps() ) { ost << "\n EXTRA INPUT " << id; }
798  for ( auto& dh : idh->outputHandles() ) { ost << "\n OUTPUT " << dh->fullKey(); }
799  for ( auto& id : idh->extraOutputDeps() ) { ost << "\n EXTRA OUTPUT " << id; }
800  if ( ost.str().length() > 0 ) { info() << "\n" << iTool->name() << ost.str(); }
801  } else {
802  error() << "can't cast " << iTool->name() << " to IDataHandleHolder!" << endmsg;
803  }
804  }
805  info() << endmsg;
806  }
807 
808  bool fail( false );
809  for ( auto& iTool : m_instancesTools ) {
810  ON_VERBOSE verbose() << iTool->name() << "::start()" << endmsg;
811 
812  if ( !iTool->sysStart().isSuccess() ) {
813  fail = true;
814  error() << iTool->name() << " failed to start()" << endmsg;
815  }
816  }
817 
818  if ( fail ) {
819  error() << "One or more AlgTools failed to start()" << endmsg;
820  return StatusCode::FAILURE;
821  }
822  return StatusCode::SUCCESS;
823 }
824 
825 //------------------------------------------------------------------------------
827 //------------------------------------------------------------------------------
828 {
829 
830  ON_DEBUG debug() << "STOP transition for AlgTools" << endmsg;
831 
832  bool fail( false );
833  for ( auto& iTool : m_instancesTools ) {
834  ON_VERBOSE verbose() << iTool->name() << "::stop()" << endmsg;
835 
836  if ( !iTool->sysStop().isSuccess() ) {
837  fail = true;
838  error() << iTool->name() << " failed to stop()" << endmsg;
839  }
840  }
841 
842  if ( fail ) {
843  error() << "One or more AlgTools failed to stop()" << endmsg;
844  return StatusCode::FAILURE;
845  }
846  return StatusCode::SUCCESS;
847 }
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
IHistorySvc::registerAlgTool
virtual StatusCode registerAlgTool(const IAlgTool &)=0
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:740
std::string
STL class.
IAlgTool
Definition: IAlgTool.h:33
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:713
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:200
ToolSvc::getInstances
std::vector< std::string > getInstances() const override
Get names of all tool instances.
Definition: ToolSvc.cpp:465
GaudiException.h
ToolSvc::existsTool
bool existsTool(std::string_view fullname) const
Check if the tool instance exists.
Definition: ToolSvc.cpp:732
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:475
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:826
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:482
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
IHistorySvc
Definition: IHistorySvc.h:43
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
ToolSvc::m_pHistorySvc
IHistorySvc * m_pHistorySvc
Pointer to HistorySvc.
Definition: ToolSvc.cpp:180
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:239
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
Definition: IConverter.h:25
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:770
IHistorySvc.h
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:203
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)
StatusCode::ignore
const StatusCode & ignore() const
Allow discarding a StatusCode without warning.
Definition: StatusCode.h:139
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:512
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:371
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:202
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:784
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:88
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:98
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.