diff --git a/Control/AthToolSupport/AsgTools/AsgTools/AnaToolHandle.h b/Control/AthToolSupport/AsgTools/AsgTools/AnaToolHandle.h index ed8e8bbbe33e0c16673b4aaddda70c413012f9f5..a4af1643eb93ad1282f6660a2f2aff33485dfb21 100644 --- a/Control/AthToolSupport/AsgTools/AsgTools/AnaToolHandle.h +++ b/Control/AthToolSupport/AsgTools/AsgTools/AnaToolHandle.h @@ -17,20 +17,343 @@ #include <AsgTools/AsgTool.h> #include <AsgTools/Deprecated.h> #include <AsgTools/ToolHandle.h> +#include <atomic> +#include <list> #include <map> +#include <mutex> namespace asg { #ifdef ROOTCORE typedef asg::AsgTool parentType_t; + typedef IAsgTool interfaceType_t; #else typedef INamedInterface parentType_t; typedef IAlgTool interfaceType_t; #endif - template<class T> class AnaToolHandle; + namespace detail + { + class AnaToolShare; + + /// \brief a class maintaining a list of cleanups to be performed + /// when releasing a tool. + + class AnaToolCleanup + { + // + // public interface + // + + /// \brief standard swap + /// \par Guarantee + /// no-fail + public: + void swap (AnaToolCleanup& that); + + + /// \brief add a cleanup to perform + /// + /// Normally this is added to the end of the list of cleanups, + /// but by passing post as false, you can also add it at the + /// beginning. + /// + /// \par Guarantee + /// basic + /// \par Failures + /// out of memory II + public: + void addCleanup (AnaToolCleanup val_cleanup, bool post = true); + + /// \copydoc addCleanup + public: + void addCleanup (const std::shared_ptr<void>& val_cleanup, + bool post = true); + + + + // + // private interface + // + + private: + std::list<std::shared_ptr<void> > m_cleanup; + }; + + + + /// \brief the base class for classes holding property values for + /// AnaToolHandle + + class AnaToolProperty + { + // + // public interface + // + + /// \brief standard default constructor for base class + /// \par Guarantee + /// no-fail + public: + virtual ~AnaToolProperty () noexcept = default; + +#ifdef ROOTCORE + /// \brief apply the property to the given tool in RootCore + /// \par Guarantee + /// basic + /// \par Failures + /// unknown property\n + /// invalid property type/value\n + /// out of memory II + public: + virtual StatusCode + applyPropertyRootCore (AsgTool& tool, const std::string& name, + AnaToolCleanup& cleanup) + const = 0; +#endif + +#ifndef ROOTCORE + /// \brief store the property in the configuration service in + /// Athena + /// \par Guarantee + /// basic + /// \par Failures + /// out of memory II + public: + virtual StatusCode + applyPropertyAthena (const std::string& toolName, + const std::string& name, + AnaToolCleanup& cleanup) + const = 0; +#endif + }; + + + + /// \brief the complete configuration for a tool + /// + /// This is very much a-kin to the python configurables used + /// inside Athena (thanks Steve Farrell for the analogy). + /// However, so far this is mostly an internal helper class for + /// the \ref AnaToolHandle implementation. + + class AnaToolConfig + { + // + // public interface + // + + /// \brief standard swap + /// \par Guarantee + /// no-fail + public: + void swap (AnaToolConfig& that) noexcept; + + + /// \brief whether we contain no properties + /// \par Guarantee + /// no-fail + public: + bool empty () const noexcept; + + + /// \brief the type of the tool to create + /// \par Guarantee + /// no-fail + public: + const std::string& type () const noexcept; + + /// \brief set the value of \ref type + /// \par Guarantee + /// no-fail + public: + void setType (std::string type) noexcept; + +#ifdef ROOTCORE + /// \brief register the new of the given type as factory + /// + /// If this is set, it is used instead of \ref type to allocate + /// the tool. This is mostly meant as a stop-gap solution for + /// tools which either do not have a dictionary, or which have a + /// class structure incompatible with instantiation via the + /// dictionary. + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory I + public: + template<typename Type> + void registerNew (); +#endif + + + /// \brief set the property with the given name in the same + /// fashion as \ref AnaToolHandle::setProperty + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II\n + /// no way to handle value + public: + template<typename Type> StatusCode + setProperty (const std::string& val_name, const Type& val_value); + + /// \copydoc setProperty + public: + template<typename Type> StatusCode + setProperty (const std::string& val_name, + const AnaToolHandle<Type>& val_value); + +#ifndef ROOTCORE + /// \copydoc setProperty + public: + template<typename Type> StatusCode + setProperty (const std::string& val_name, + const ToolHandle<Type>& val_value); + + /// \copydoc setProperty + public: + template<typename Type> StatusCode + setProperty (const std::string& val_name, + const ToolHandleArray<Type>& val_value); +#endif + + + /// \copydoc setProperty + public: + StatusCode + setProperty (const std::string& val_name, + const char *val_value); + + + /// \brief add/set the property with the given name + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + public: + void addProperty (const std::string& name, + const std::shared_ptr<AnaToolProperty>& property); + + + /// \brief make a configured and initialized tool + /// \par Guarantee + /// strong + /// \par Failures + /// tool creation failures + public: + template<typename ToolType> StatusCode + makeTool (const std::string& name, + parentType_t *parent, + ToolHandle<ToolType>& th, + AnaToolCleanup& cleanup) const; + + + /// \brief make a configured and initialized tool of the basic type + /// \par Guarantee + /// strong + /// \par Failures + /// tool creation failures + public: + StatusCode + makeBaseTool (const std::string& name, + parentType_t *parent, + ToolHandle<interfaceType_t>& th, + AnaToolCleanup& cleanup) const; + + +#ifndef ROOTCORE + /// \brief store the properties in the configuration service in + /// Athena + /// \par Guarantee + /// basic + /// \par Failures + /// out of memory II + public: + StatusCode + applyPropertiesAthena (const std::string& toolName, + AnaToolCleanup& cleanup) const; +#endif + + + + // + // private interface + // + + /// \brief the value of \ref type + private: + std::string m_type; + + /// \brief the factory to use, if we have one + private: + std::function<StatusCode (AsgTool*&, const std::string&)> m_factory; + + /// \brief the list of all properties stored + private: + std::map<std::string,std::shared_ptr<AnaToolProperty> > m_properties; + + +#ifdef ROOTCORE + /// \brief create, configure and initialize the tool (in + /// RootCore) + /// \par Guarantee + /// strong + /// \par Failures + /// tool creation/initialization failures + private: + StatusCode + makeToolRootCore (const std::string& toolName, IAsgTool*& toolPtr, + detail::AnaToolCleanup& cleanup) const; +#endif + + +#ifdef ROOTCORE + /// \brief allocate the tool + /// \par Guarantee + /// basic + /// \par Failures + /// tool allocation failures + private: + StatusCode + allocateTool (AsgTool*& toolPtr, const std::string& toolName) const; +#endif + }; + + + + /// \brief the mode with which an \ref AnaToolHandle object is + /// initialized + + enum class AnaToolHandleMode + { + /// do not create a tool + /// + /// this can be either explicitly an empty tool handle set by + /// the user, or an AnaToolHandle that was never configured in + /// the first place. + EMPTY, + + /// create a private tool normally + CREATE_PRIVATE, + + /// create a shared tool normally + CREATE_SHARED, + + /// retrieve a shared tool + RETRIEVE_SHARED, + + /// retrieve a tool from the user tool handle + /// + /// this can still refer to a tool handle that is empty, though + /// usually it will point to an actual tool + USER + }; + } + + /// \brief standard output operator /// \par Guarantee @@ -71,26 +394,27 @@ namespace asg /// off by the complexity of Athena configuration. /// /// - /// Conceptually this tools tries to model an std::unique_ptr or - /// std::shared_ptr, for which calls to new, setProperty and - /// initialize have been wrapped to make them dual-use as well as - /// safer to use. If a parent tool is specified, the tool is - /// private (and this tool handle is modeled after unique_ptr). If - /// no parent tool is specified, the tool is public/shared (and this - /// tool handle is modeled after shared_ptr). + /// The basic interface is a mix between the ToolHandle interface + /// for accessing the tool, and the AsgTool interface for + /// configuring/initializing the tools. In addition it allows to + /// set this ToolHandle as a property on another configurable, to + /// allow configuring it via the standard configuration mechanisms. /// - /// In public/shared mode, if you create and initialize one tool it - /// is then available for use by other tool handles registered with - /// the same name and type. The subsequent tool handles with that - /// name will then automatically pick up the tool in the - /// configuration set by the first tool handle. The user still has - /// to call initialize() on the tool handle before using the tool. - /// While it is allowed to call setProperty* method on those tool - /// handles these calls will be effectively ignored. The net effect - /// of that is that as a user of a handle for a shared tool you - /// don't have to worry about whether you are the one creating the - /// tool or just using it, you just initialize the tool handle in - /// the same way. + /// If a parent tool is specified, the tool is private (and this + /// tool handle is modeled after unique_ptr). If no parent tool is + /// specified, the tool is public/shared (and this tool handle is + /// modeled after shared_ptr). In public/shared mode, if you create + /// and initialize one tool it is then available for use by other + /// tool handles registered with the same name and type. The + /// subsequent tool handles with that name will then automatically + /// pick up the tool in the configuration set by the first tool + /// handle. The user still has to call initialize() on the tool + /// handle before using the tool. While it is allowed to call the + /// setProperty method on those tool handles these calls will be + /// effectively ignored. The net effect of that is that as a user + /// of a handle for a shared tool you don't have to worry about + /// whether you are the one creating the tool or just using it, you + /// just initialize the tool handle in the same way. /// /// The tool handle can also be declared as a property on the parent /// tool by using the ToolHandle provided via its handle member @@ -104,6 +428,24 @@ namespace asg /// you can just write your code as if the user didn't configure /// your tool handle and if the user does, the tool handle will /// automatically switch over. + /// + /// + /// There are a number of ways of how a tool can be created/accessed + /// through an AnaToolHandle (in *increasing* order of precedence): + /// - normally an AnaToolHandle will create its tool based on the + /// configured type and properties under the configured name. + /// - if an AnaToolHandle has been created without a parent (i.e. as + /// a public tool) and another AnaToolHandle already has created a + /// public tool with the same name it will use and share that + /// already configured tool. + /// - each AnaToolHandle can be declared as a property on the parent + /// tool, allowing to configure the AnaToolHandle that way. if + /// the user configures the AnaToolHandle that way, it will take + /// precedence over any properties set on the AnaToolHandle. + /// - for the future it is foreseen to provide a second property on + /// the parent tool to allow the user picking a particular + /// creation or access pattern, overriding the auto-detected + /// default template<class T> class AnaToolHandle final @@ -138,21 +480,42 @@ namespace asg /// \par Guarantee /// no-fail public: - AnaToolHandle (AnaToolHandle<T>&& that) noexcept; + AnaToolHandle (AnaToolHandle<T>&& that); + + + /// \brief copy constructor + /// + /// This will copy the configuration if the argument has not been + /// initialized yet, and it will create a shared tool handle if it + /// has. + /// + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + public: + AnaToolHandle (const AnaToolHandle<T>& that); /// \brief standard destructor /// \par Guarantee /// no-fail public: - ~AnaToolHandle (); + ~AnaToolHandle () noexcept; - /// \brief standard swap + /// \brief assignment operator + /// + /// This will copy the configuration if the argument has not been + /// initialized yet, and it will create a shared tool handle if it + /// has. + /// /// \par Guarantee - /// no-fail + /// strong + /// \par Failures + /// out of memory II public: - void swap (AnaToolHandle<T>& that); + AnaToolHandle& operator = (const AnaToolHandle<T>& that); /// \brief standard move assignment operator @@ -162,43 +525,55 @@ namespace asg AnaToolHandle<T>& operator = (AnaToolHandle<T>&& that); - /// \brief make a new tool of the type specified in the - /// constructor + /// \brief standard swap /// \par Guarantee - /// strong - /// \par Failures - /// tool creation failures\n - /// no tool type specified - /// \pre tool has not yet been created + /// no-fail public: - StatusCode make (); + void swap (AnaToolHandle<T>& that) noexcept; - /// \brief make a new tool of the given type + + /// \brief whether this ToolHandle is completely empty, i.e. it + /// has been default constructed and was never assigned any + /// content by the user /// - /// The type name can either be just the type itself or be of the - /// form type/name, in which case name indicates the name of the - /// tool to be created. /// \par Guarantee /// strong /// \par Failures - /// tool creation failures - /// \pre tool has not yet been created + /// out of memory II public: - StatusCode make (const std::string& typeName); + bool empty () const; - /// \brief make a new tool of the given type + /// \brief whether this is a public tool (or tool handle) /// \par Guarantee - /// strong + /// no-fail + public: + bool isPublic () const noexcept; + + /// \brief whether initialize has been called successfully, + /// i.e. whether the tool is ready to be used + /// \par Guarantee + /// no-fail + public: + bool isInitialized () const noexcept; + + + /// \brief declare as property on the given tool + /// \par Guarantee + /// basic /// \par Failures - /// tool creation failures - /// \pre tool has not yet been created - /// \warn this is only for legacy support and even then should - /// only be called via the \ref ASG_MAKE_ANA_TOOL macro + /// out of memory II\n + /// property declaration failures\n + /// tool already made public: -#ifdef ROOTCORE - template<class T2> - StatusCode makeNew (std::string val_type); -#endif + template<typename T2> void + declarePropertyFor (T2 *tool, const std::string& name, + const std::string& description = ""); + + /// \brief the tool handle we wrap + /// \par Guarantee + /// no-fail + public: + const ToolHandle<T>& getHandle () const noexcept; /// \brief set the given property of the tool. @@ -216,125 +591,157 @@ namespace asg /// basic /// \par Failures /// property setting failures - /// \pre tool has not yet been initialized + /// \pre !isInitialized() public: template <class T2> StatusCode setProperty (const std::string& property, const T2& value); - /// \copydoc setProperty - public: - template <class T2> StatusCode - setProperty (const std::string& property, const ToolHandle<T2>& tool); - /// \copydoc setProperty + /// \brief the type configured for this AnaToolHandle + /// \par Guarantee + /// no-fail public: - template <class T2> StatusCode - setProperty (const std::string& property, const AnaToolHandle<T2>& tool); + const std::string& type () const noexcept; + /// \brief set the value of \ref type + /// \par Guarantee + /// no-fail + /// \pre !isInitialized() + public: + void setType (std::string val_type) noexcept; -#ifndef ROOTCORE //implementation for cmt releases only so far, I think rootcore releases will already work ~ok - /// \copydoc setProperty +#ifdef ROOTCORE + /// \brief set the value of \ref type and a factory based on the + /// standard tool constructor + /// + /// This is mainly for use with RootCore where we occasionally + /// have trouble instantiating tools via their dictionaries. Even + /// in that case you shouldn't call this directly, but use the + /// \ref ASG_MAKE_ANA_TOOL macro. + /// + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory I public: - template <class T2> StatusCode - setProperty (const std::string& property, const ToolHandleArray<T2>& tool); + template<class T2> + void setTypeRegisterNew (std::string val_type); #endif - /// \brief initialize the tool + /// \brief the name configured for this AnaToolHandle /// \par Guarantee - /// basic - /// \par Failures - /// tool initialization failures - /// \pre tool has not yet initialized + /// no-fail public: - StatusCode initialize (); + const std::string& name () const noexcept; - /// \brief retrieve (i.e. initialize) the tool + /// \brief set the value of \ref name /// \par Guarantee - /// basic + /// no-fail + /// \pre !isInitialized() + public: + void setName (std::string val_name) noexcept; + + /// \brief the full name of the tool to be used during tool + /// initialization + /// \par Guarantee + /// strong /// \par Failures - /// tool initialization failures - /// \pre tool has not yet initialized + /// out of memory II public: - StatusCode retrieve (); + std::string fullName () const; - /// \brief access the tool + /// \brief the value of \ref type and \ref name /// \par Guarantee - /// no-fail - /// \pre isInitialized() - /// \post result != nullptr + /// strong + /// \par Failures + /// out of memory II public: - T *operator -> () const noexcept; + std::string typeAndName () const; - /// \brief access the tool + /// \brief set the value of \ref type and \ref name /// \par Guarantee - /// no-fail - /// \pre isInitialized() + /// strong + /// \par Failures + /// out of memory II + /// \pre !isInitialized() public: - T& operator * () const noexcept; + void setTypeAndName (const std::string& val_typeAndName); - /// \brief access the tool + /// \brief set the value of \ref type and \ref name /// \par Guarantee /// no-fail - /// \pre isInitialized() - /// \post result != nullptr + /// \pre !isInitialized() public: - T *get () const noexcept; + void setTypeAndName (std::string val_type, std::string val_name) noexcept; - /// \brief declare as property on the given tool + /// \brief initialize the tool /// \par Guarantee /// strong /// \par Failures - /// out of memory II\n - /// property declaration failures\n - /// tool already made + /// tool initialization failures + /// \pre !isInitialized() public: - template<typename T2> void - declarePropertyFor (T2 *tool, const std::string& name, - const std::string& description = ""); + StatusCode initialize (); + /// \copydoc initialize + public: + StatusCode retrieve (); - /// \brief the type configured for this AnaToolHandle + + /// \brief access the tool /// \par Guarantee - /// no-fail + /// strong + /// \par Failures + /// tool creation failures + /// \post result != nullptr public: -#ifdef ROOTCORE - const std::string& type () const noexcept; -#else - std::string type () const; -#endif + T *operator -> (); - /// \brief the name configured for this AnaToolHandle + /// \brief access the tool /// \par Guarantee - /// no-fail + /// strong + /// \par Failures + /// tool creation failures + /// \post result != nullptr public: -#ifdef ROOTCORE - const std::string& name () const noexcept; -#else - std::string name () const; -#endif + const T *operator -> () const; + /// \brief access the tool + /// \par Guarantee + /// strong + /// \par Failures + /// tool creation failures + public: + T& operator * (); - /// \brief the tool handle we wrap + /// \brief access the tool /// \par Guarantee - /// no-fail + /// strong + /// \par Failures + /// tool creation failures public: - const ToolHandle<T>& getHandle () const noexcept; + const T& operator * () const; + /// \brief access the tool + /// \par Guarantee + /// strong + /// \par Failures + /// tool creation failures + /// \post result != nullptr + public: + T *get (); - /// \brief the tool handle we can expose to the configuration - /// mechanism - /// - /// This allows to register this AnaToolHandle like a regular - /// ToolHandle via declareProperty(). If it is set during - /// configuration it will then replace anything provided by - /// calling \ref make or \ref setProperty on this AnaToolHandle. + /// \brief access the tool /// \par Guarantee - /// no-fail + /// strong + /// \par Failures + /// tool creation failures + /// \post result != nullptr public: - ToolHandle<T>& handle (); + const T *get () const; /// \brief whether this tool handle has been configured by the @@ -349,47 +756,113 @@ namespace asg bool isUserConfigured () const noexcept; - /// \brief whether the tool can be configured by us + /// \brief the \ref detail::AnaToolHandleMode for this handle + /// + /// This is mostly meant for internal use by the setProperty + /// method, not for use by the end-user /// - /// if this refers to a shared tool or has been configured via the - /// ToolHandle, then we can't configure the tool ourselves. we - /// can still call the setProperty methods, they just won't do - /// anything. /// \par Guarantee - /// no-fail + /// strong + /// \par Failures + /// out of memory II public: - bool isConfigurable () const; + detail::AnaToolHandleMode mode () const; - /// \brief whether initialize has been called successfully, - /// i.e. whether the tool is ready to be used + /// \brief the \ref detail::AnaToolConfig for this handle + /// + /// This is mostly meant for internal use by the setProperty + /// method, not for use by the end-user + /// /// \par Guarantee - /// no-fail + /// strong + /// \par Failures + /// out of memory II public: - bool isInitialized () const noexcept; + const detail::AnaToolConfig& config () const; - /// \brief whether we are in the state before calling make + /// \brief whether the user is allowed to configure this with an + /// empty tool handle + /// + /// This normally defaults to whether the developer initialized + /// this to a valid ToolHandle to begin with, but depending on the + /// situation it can be overridden. /// - /// Normally users don't need to check this, but sometimes this - /// can be worthwhile to check for debugging purposes. /// \par Guarantee /// no-fail public: - bool inPremakeState () const noexcept; + bool allowEmpty () const noexcept; + + + /// \brief set the value of \ref allowEmpty + /// \par Guarantee + /// no-fail + /// \pre !isInitialized() + public: + void setAllowEmpty (bool val_allowEmpty = true) noexcept; + + + + // + // deprecated interface + // - /// \brief whether we are in a broken state + /// \brief whether the tool can be configured by us, i.e. whether + /// properties set via \ref setProperty will be used for something + /// + /// For the most part this is the reverse of \ref isUserConfigured + /// except some shared tools may register as not user configured + /// and not configurable either. if the properties set are used + /// to generate debugging output even a user configured tool may + /// register as configurable. /// - /// Normally users don't need to check this, but sometimes this - /// can be worthwhile to check for debugging purposes. Normally - /// tools get into a broken state either because one of the - /// configuration functions failed, or because the content of this - /// object was moved to another tool handle. /// \par Guarantee /// no-fail + /// \warn this may go away at some point as we may be using the + /// properties for more and more things (e.g. info printouts) + public: + bool isConfigurable () const; + + public: + ASG_DEPRECATED ("please use isInitialized() instead") + bool inPremakeState () const noexcept { + return !isInitialized();} + + public: + ASG_DEPRECATED ("please use isInitialized() instead") + bool inBrokenState () const noexcept { + return false;}; + + public: + ASG_DEPRECATED ("no longer need to call make()") + StatusCode make () { + return StatusCode::SUCCESS;}; + + public: + ASG_DEPRECATED ("please use setType() or setTypeAndName() instead") + StatusCode make (std::string val_type) noexcept { + if (!val_type.empty()) { + if (val_type.find ('/') != std::string::npos) + setTypeAndName (val_type); + else + setType (val_type); } + return StatusCode::SUCCESS; }; + public: - bool inBrokenState () const noexcept; + ASG_DEPRECATED ("please use either getHandle() or declarePropertyFor() instead") + ToolHandle<T>& handle () { + return *m_handleUser;}; + +#ifdef ROOTCORE + public: + template<class T2> + ASG_DEPRECATED ("please use setTypeRegisterNew() instead") + StatusCode makeNew (std::string val_type) { + setTypeRegisterNew<T2> (std::move (val_type)); + return StatusCode::SUCCESS;} +#endif @@ -397,64 +870,42 @@ namespace asg // private interface // - /// \brief the different states of the tool handle + /// \brief any stuff we need to release as part of cleanup + /// + /// This is protected by \ref m_isInitialized and should not be + /// accessed until \ref m_isInitialized is true. private: - enum class State - { - /// \brief the beginning state - BEGIN, - - /// \brief we are using a pre-initialized tool, i.e. we ignore - /// all setProperty() requests and initialize() essentially just - /// unlocks it - PREINITIALIZED, - - /// \brief the tool has been made, but not initialized - CREATED, + detail::AnaToolCleanup m_cleanup; - /// \brief the tool has been initialized and can be used - INITIALIZED, + /// \brief the configuration for this tool + private: + detail::AnaToolConfig m_config; - /// \brief we encountered an error in setProperty - /// - /// This is to emulate the Athena behavior in RootCore, - /// i.e. that setProperty failures only show up when actually - /// initializing the tool, not when setting properties on it. - BAD_PROPERTY, + /// \brief the value of \ref name + private: + std::string m_name; - /// \brief an error has occurred in the tool creation process - BROKEN - }; + /// \brief the name of the parent + private: + std::string m_parentName; - /// \brief the current \ref State of the tool handle + /// \brief the pointer to the parent private: - State m_state = State::BEGIN; + parentType_t *m_parentPtr = nullptr; - /// \brief the \ref ToolHandle we wrap our tool handle around + /// \brief the \ref ToolHandle exposed to the user /// - /// This serves as a backend for a lot of our functions, and we - /// rely on its properties as much as possible instead of trying - /// to implement our own. As such we purposely limit write access - /// by the user to this handle. It can be declared as a property - /// on the parent tool and set during the configuration stage, but - /// otherwise it is off-limits to the user. + /// This primarily serves to allow the user to set this like a + /// regular ToolHandle property. During initialize it is then + /// updated to refer to the actually used tool. /// /// This is done as a shared pointer, so that the include /// dependency is only pulled in for the source file that actually /// uses the AnaToolHandle. That in turn reduces the number of /// public dependencies an Athena package has to expose. private: - std::shared_ptr<ToolHandle<T>> m_handle; - - - /// \brief the parent of the tool - /// - /// in RootCore we can not ask the ToolHandle for the pointer to - /// the parent, so instead we cache it here and just check in - /// Athena that it is the same as in the ToolHandle - private: - parentType_t *m_parent = nullptr; + std::shared_ptr<ToolHandle<T>> m_handleUser; /// \brief the typeAndName at time of creation /// @@ -463,152 +914,88 @@ namespace asg private: std::string m_originalTypeAndName; + /// \brief the value of \ref isInitialized + private: + std::atomic<bool> m_isInitialized {false}; + /// \brief the pointer to the tool we use /// /// This is used for actually accessing the tool, independent of - /// how we created it. + /// who created it or how. Mostly this is a performance + /// optimization to avoid going back to the ToolHandle every + /// single time. + /// + /// This is protected by \ref m_isInitialized and should not be + /// accessed until \ref m_isInitialized is true. private: T *m_toolPtr = nullptr; - /// \brief the value of \ref isUserConfigured cached when we make - /// the tool - private: - bool m_isUserConfigured = false; - - - /// \brief do all the checks that need to be done before running - /// any version of make - /// \par Guarantee - /// basic - /// \par Failures - /// tool creation failures\n - /// pre-condition failures - private: - StatusCode - preMake (const std::string& val_type); - - /// \brief actually make the tool, if we make our own - /// \par Guarantee - /// basic - /// \par Failures - /// tool creation failures\n - /// pre-condition failures - private: - StatusCode - doMake (); - - - /// \brief do all the checks that need to be done before running - /// any version of setProperty - /// \par Guarantee - /// basic - /// \par Failures - /// tool creation failures\n - /// pre-condition failures - private: - StatusCode preSetProperty (const std::string& property); - - - - // - // private interface for RootCore - // - -#ifdef ROOTCORE - /// \brief the pointer to the tool used for configuration - private: - asg::AsgTool *m_toolConfig = nullptr; - - /// \brief the smart pointer to the tool, if we created it - /// ourselves + /// \brief the value of \ref getMode cached when we initialize the + /// tool /// - /// If we create the tool ourselves, we are responsible for - /// cleaning it up. Originally this was a unique_ptr, but I - /// changed it to a shared pointer, so that it users don't have to - /// include all the possible tool classes in their code. Also, - /// this allows to share a tool between multiple \ref - /// AnaToolHandle objects. + /// This is protected by \ref m_isInitialized and should not be + /// accessed until \ref m_isInitialized is true. private: - std::shared_ptr<T> m_toolOwn; + detail::AnaToolHandleMode m_mode = detail::AnaToolHandleMode::EMPTY; - /// \brief the weak pointer referencing shared tools + /// \brief get the mode with which this ToolHandle will be initialized + /// + /// This exists in two modes, one passing back a shared tool + /// pointer and one without it. as a rule of thumb, the version + /// passing back the shared tool should be used by initialize, + /// whereas all the places just wanting to check that will happen + /// can/should call the version without. + /// /// \par Guarantee /// strong /// \par Failures /// out of memory II - /// \brief !m_name.empty() private: - std::weak_ptr<T>& sharedToolPointer () const; -#endif - - + detail::AnaToolHandleMode + getMode (std::shared_ptr<detail::AnaToolShare>& sharedTool) const; - // - // private interface for Athena - // - -#ifndef ROOTCORE + /// \copydoc getMode private: - std::vector<std::string> m_addedProperties; + detail::AnaToolHandleMode + getMode () const; - // \brief this contains a release function we use, so that we can - // break down on include dependencies - private: - std::function<void (ToolHandle<T> *)> m_releaseFunction; + /// \brief the value of \ref allowEmpty private: - std::string fullName () const; -#endif - - - - // - // legacy interface - // - - // prevent copying - AnaToolHandle (const AnaToolHandle<T>&) = delete; - AnaToolHandle<T>& operator = (const AnaToolHandle<T>&) = delete; + bool m_allowEmpty = false; - /// \brief whether this ToolHandle is completely empty + /// \brief make a tool by retrieving the ToolHandle /// \par Guarantee - /// no-fail - public: - bool empty() const noexcept; - - - private: - void setType (std::string val_type) { - setTypeAndName (std::move (val_type), name());} - + /// strong + /// \par Failures + /// tool creation failures private: - void setName (std::string val_name) { - setTypeAndName (type(), std::move (val_name));} + StatusCode makeToolRetrieve + (T*& toolPtr, ToolHandle<T>& toolHandle) const; - private: - void setTypeAndName (std::string val_type, - std::string val_name) { - if (val_type.empty()) - m_handle->setTypeAndName (std::move (val_type)); - else if (val_name.empty()) - m_handle->setTypeAndName (std::move (val_name)); - else - m_handle->setTypeAndName (val_type + "/" + val_name);} + /// \brief a mutex to ensure that we don't call initialize twice + /// concurrently + /// + /// This is a recursive mutex so that we can lock both in \ref + /// initialize and \ref get without conflict. private: - void setTypeAndName (std::string val_typeAndName) { - m_handle->setTypeAndName (std::move (val_typeAndName));} + std::recursive_mutex m_initializeMutex; }; } /// \brief create the tool in the given tool handle -#ifdef ROOTCORE #define ASG_MAKE_ANA_TOOL(handle,type) \ - (handle).template makeNew<type> (#type) + (ASG_SET_ANA_TOOL_TYPE(handle,type), StatusCode (StatusCode::SUCCESS)) + +/// \brief set the tool type on the tool handle, using new in rootcore +#ifdef ROOTCORE +#define ASG_SET_ANA_TOOL_TYPE(handle,type) \ + (handle).template setTypeRegisterNew<type> (#type) #else -#define ASG_MAKE_ANA_TOOL(handle,type) \ - (handle).make (#type) +#define ASG_SET_ANA_TOOL_TYPE(handle,type) \ + (handle).setType (#type) #endif #include <AsgTools/AnaToolHandle.icc> diff --git a/Control/AthToolSupport/AsgTools/AsgTools/AnaToolHandle.icc b/Control/AthToolSupport/AsgTools/AsgTools/AnaToolHandle.icc index 82ea4c2d14d4c31df7f0ea337658813bc0aead65..6166713f0ee9ddafea33408e544a8996cd6d7aad 100644 --- a/Control/AthToolSupport/AsgTools/AsgTools/AnaToolHandle.icc +++ b/Control/AthToolSupport/AsgTools/AsgTools/AnaToolHandle.icc @@ -23,481 +23,770 @@ namespace asg StatusCode toolExists( const std::string& fullName, interfaceType_t*& tool ); // StatusCode factoryExists( const std::string& type ); #endif - } - - - - template <typename T> - std::ostream& operator << (std::ostream& str, const AnaToolHandle<T>& obj) - { - return str << obj.getHandle(); - } - template<class T> void AnaToolHandle<T> :: - testInvariant () const - { -#define CHECK_INVARIANT(x) \ - if (!(x)) { std::cerr << __FILE__ << ":" << __LINE__ << ": invariant violated: " << #x << std::endl; std::abort(); } + /// \brief do a checked cast from one ToolHandle interface to + /// another + /// \par Guarantee + /// basic + /// \par Failures + /// interface not supported for tool + template<typename T1,typename T2> StatusCode + toolHandleCast (ToolHandle<T1>& to, ToolHandle<T2>& from) + { + using namespace msgUserCode; - // General requirements - CHECK_INVARIANT (&*this != nullptr); - CHECK_INVARIANT (m_handle != nullptr); #ifdef ROOTCORE - CHECK_INVARIANT (m_toolOwn == nullptr || m_toolOwn.get() == m_toolPtr); + to = ToolHandle<T1> (dynamic_cast<T1*>(&*from)); + if (!from.empty() && &*to == nullptr) + { + ANA_MSG_ERROR ("failed to cast from type " << typeid(T2).name() << " to " << typeid(T1).name()); + return StatusCode::FAILURE; + } #else - CHECK_INVARIANT (m_parent == m_handle->parent()); - CHECK_INVARIANT (m_releaseFunction); + to = ToolHandle<T1> (from.typeAndName(), from.parent()); + if (!from.empty()) + ANA_CHECK (to.retrieve()); #endif + return StatusCode::SUCCESS; + } + + + - // State-dependent requirements - switch (m_state) + + /// \brief the information needed to share a tool + + class AnaToolShare { - case State::BEGIN: - break; - case State::PREINITIALIZED: - CHECK_INVARIANT (m_toolPtr != nullptr); - CHECK_INVARIANT (m_isUserConfigured == true); - break; - case State::CREATED: -#ifdef ROOTCORE - CHECK_INVARIANT (m_toolPtr != nullptr); - CHECK_INVARIANT (m_toolConfig != nullptr); -#endif - CHECK_INVARIANT (m_isUserConfigured == false); - break; - case State::INITIALIZED: - CHECK_INVARIANT (m_toolPtr != nullptr); - break; - case State::BAD_PROPERTY: - CHECK_INVARIANT (m_toolPtr != nullptr); - break; - case State::BROKEN: - break; - } + // + // public interface + // -#undef CHECK_INVARIANT - } + /// \brief standard constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + public: + AnaToolShare (const ToolHandle<interfaceType_t>& val_th, + AnaToolCleanup val_cleanup); + + + /// \brief the tool we contain + /// \par Guarantee + /// no-fail + /// \post result != nullptr + public: + ToolHandle<interfaceType_t>& th (); + + + + // + // private interface + // + + /// \brief the value of \ref tool + private: + ToolHandle<interfaceType_t> m_th; + + /// \brief resources to release shen we are releasing the tool + private: + AnaToolCleanup m_cleanup; + }; + + + + + + /// \brief a service for sharing tools of a given type + + class AnaToolShareList + { + // + // public interface + // + + /// \brief the singleton we are using + /// \par Guarantee + /// no-fail + public: + static AnaToolShareList& singleton () noexcept; + + + /// \brief get the share for the given name, or nullptr if no + /// share has been defined + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory I + public: + std::shared_ptr<AnaToolShare> + getShare (const std::string& name) const; + + + /// \brief set the share for the given name + /// \return the share to use, this is either the share passed in + /// or the already set share + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + private: + std::shared_ptr<AnaToolShare> + setShare (const std::string& name, + std::unique_ptr<AnaToolShare> val_share); + + + /// \brief make or get a share for the given name + /// \return the share to use, either freshly created or + /// retrieved from the store + /// \par Guarantee + /// strong + /// \par Failures + /// tool creation failures\n + /// out of memory II + public: + StatusCode + makeShare (const std::string& name, + const AnaToolConfig& config, + std::shared_ptr<AnaToolShare>& result); + + + + // + // private interface + // + + /// \brief the shares we manage + private: + std::map<std::string,std::weak_ptr<AnaToolShare> > m_shared; + }; - template<class T> AnaToolHandle<T> :: - AnaToolHandle (const std::string& val_name, parentType_t *val_parent) - : m_handle (new ToolHandle<T> (val_name, val_parent)), - m_parent (val_parent), - m_originalTypeAndName (m_handle->typeAndName ()) #ifndef ROOTCORE - , m_releaseFunction ([] (ToolHandle<T> *m_handle) { - using namespace msgToolHandle; - //tool has 2 ref counts out of the box?? (ToolSvc and, and ToolSvc again because of the queryInterface call (line 348 of ToolSvc.cpp .. and see line 34 of AlgTool.cpp)) - if(m_handle->isSet()) { - //before deleting, check ToolSvc still knows about it, because it might already have been destroyed by ToolSvc finalize - interfaceType_t *tool = nullptr; - if( !detail::toolExists( m_handle->parentName() + "." + m_handle->name(), tool ) ) return; //already deleted - ANA_MSG_DEBUG( *m_handle << " " << (*m_handle)->refCount() ); - //if((*m_handle)->refCount()==3) (*m_handle)->release(); //may cause problem if the other 'something' wants to use the tool still?? - //ANA_MSG_DEBUG (*m_handle << " " << (*m_handle)->refCount()); - if((*m_handle)->refCount()==2) (*m_handle)->release(); //may cause problem if the other 'something' wants to use the tool still?? - ANA_MSG_DEBUG (*m_handle << " " << (*m_handle)->refCount()); - m_handle->release().ignore(); //triggers tool destruction - } - }) -#endif - { -#ifndef NDEBUG - this->testInvariant (); + /// \brief manage a single property in the job options service + + struct PropertyValueManager + { + PropertyValueManager (const std::string& val_toolName, + const std::string& val_name) + : m_toolName (val_toolName), m_name (val_name) + { + } + + ~PropertyValueManager () + { + if (m_cleanup) + detail::removePropertyFromCatalogue (m_toolName, m_name).ignore(); + } + + std::string m_toolName; + std::string m_name; + bool m_cleanup = false; + }; + + + + /// \brief a \ref AnaToolProperty containing a regular value for + /// Athena + + class AnaToolPropertyValueAthena : public AnaToolProperty + { + public: + template<typename Type> + AnaToolPropertyValueAthena (const Type& val_value) + : m_value (Gaudi::Utils::toString (val_value)) + { + } + + public: + virtual StatusCode + applyPropertyAthena (const std::string& toolName, + const std::string& name, + AnaToolCleanup& cleanup) + const override; + + private: + std::string m_value; + }; #endif - } - template<class T> AnaToolHandle<T> :: - AnaToolHandle (AnaToolHandle<T>&& that) noexcept - : m_state (that.m_state), - m_handle (that.m_handle), - m_parent (that.m_parent), - m_originalTypeAndName (std::move (that.m_originalTypeAndName)), - m_toolPtr (that.m_toolPtr), - m_isUserConfigured (that.m_isUserConfigured), + + #ifdef ROOTCORE - m_toolConfig (that.m_toolConfig), - m_toolOwn (std::move (that.m_toolOwn)) -#else - m_addedProperties (std::move (that.m_addedProperties)), - m_releaseFunction (that.m_releaseFunction) -#endif - { - that.m_state = State::BROKEN; + /// \brief a \ref AnaToolProperty containing a regular value in + /// RootCore -#ifndef NDEBUG - that.testInvariant (); - testInvariant (); + template<typename Type> + class AnaToolPropertyValueRootCore : public AnaToolProperty + { + public: + AnaToolPropertyValueRootCore (const Type& val_value) + : m_value (val_value) + {} + + public: + virtual StatusCode + applyPropertyRootCore (AsgTool& tool, const std::string& name, + AnaToolCleanup& /*cleanup*/) + const override + { + using namespace msgToolHandle; + ANA_CHECK (tool.setProperty (name, m_value)); + return StatusCode::SUCCESS; + } + + private: + Type m_value; + }; #endif - } - template<class T> void AnaToolHandle<T> :: - swap (AnaToolHandle<T>& that) - { -#ifndef NDEBUG - testInvariant (); - that.testInvariant (); -#endif - std::swap (m_state, that.m_state); - m_handle.swap (that.m_handle); - std::swap (m_parent, that.m_parent); - m_originalTypeAndName.swap (that.m_originalTypeAndName); - std::swap (m_toolPtr, that.m_toolPtr); - std::swap (m_isUserConfigured, that.m_isUserConfigured); + + /// \brief a \ref AnaToolProperty containing an \ref AnaToolConfig + /// for configuring a private sub-tool + + template<typename Type> + class AnaToolPropertyPrivateTool : public AnaToolProperty + { + public: + AnaToolPropertyPrivateTool (const AnaToolConfig& val_config) + : m_config (val_config) + {} + #ifdef ROOTCORE - std::swap (m_toolConfig, that.m_toolConfig); - m_toolOwn.swap (that.m_toolOwn); -#else - m_addedProperties.swap (that.m_addedProperties); - m_releaseFunction.swap (that.m_releaseFunction); + public: + virtual StatusCode + applyPropertyRootCore (AsgTool& tool, const std::string& name, + AnaToolCleanup& cleanup) + const override + { + using namespace msgToolHandle; + ToolHandle<Type> th; + AnaToolCleanup mycleanup; + ANA_CHECK (m_config.makeTool (name, &tool, th, mycleanup)); + cleanup.addCleanup (std::move (mycleanup)); + ANA_CHECK (tool.setProperty (name, th)); + return StatusCode::SUCCESS; + } #endif -#ifndef NDEBUG - testInvariant (); - that.testInvariant (); +#ifndef ROOTCORE + private: + virtual StatusCode + applyPropertyAthena (const std::string& toolName, + const std::string& name, + AnaToolCleanup& cleanup) + const override + { + using namespace msgToolHandle; + ANA_CHECK (m_config.applyPropertiesAthena (toolName + "." + name, cleanup)); + + // this is so we clear out properties from catalogue when tool + // is destroyed. DISABLED: as we no longer release tools in Athena + // std::shared_ptr<PropertyValueManager> manager + // (new PropertyValueManager (th.name(), name)); + // cleanup.addCleanup (manager); + + // for athena we hand our property to the joboptions svc + ANA_CHECK (detail::addPropertyToCatalogue (toolName, name, m_config.type() + "/" + name)); + // manager->m_cleanup = true; + return StatusCode::SUCCESS; + } #endif - } - + private: + AnaToolConfig m_config; + }; - template<class T> AnaToolHandle<T>& AnaToolHandle<T> :: - operator = (AnaToolHandle<T>&& that) - { - // no invariant used - swap (that); - return *this; - } - template<class T> AnaToolHandle<T> :: - ~AnaToolHandle () - { - using namespace msgToolHandle; -#ifndef NDEBUG - this->testInvariant (); -#endif #ifndef ROOTCORE + /// \brief a \ref AnaToolProperty copying a tool configuration + /// from the job options service to a new place + + class AnaToolPropertyCopyTool : public AnaToolProperty + { + public: + AnaToolPropertyCopyTool (const std::string& val_type, + const std::string& val_name); - // if we caused properties to be set in the catalogue, we must - // cleanup too - for (auto& prop : m_addedProperties) - detail::removePropertyFromCatalogue( fullName() , prop ).ignore(); + private: + virtual StatusCode + applyPropertyAthena (const std::string& toolName, + const std::string& name, + AnaToolCleanup& cleanup) + const override; - if (m_releaseFunction) - m_releaseFunction (m_handle.get()); + /// \brief the type of the tool to create + private: + std::string m_type; + /// \brief the name of the source tool + private: + std::string m_name; + }; #endif - } - template<class T> bool - AnaToolHandle<T> :: - empty () const noexcept - { - //handle is empty if: it wasn't user configured and our type and name are not set, or it is user configured and the member handle is empty - return( ( isUserConfigured() && ( m_handle->empty() || m_handle->typeAndName()=="PublicToolHandle('')" || m_handle->typeAndName()=="PrivateToolHandle('')" ) ) - || ( (!isUserConfigured() && type()=="" && name()=="") ) ); - } + /// \brief a \ref AnaToolProperty containing an \ref AnaToolConfig + /// for configuring a public sub-tool + + template<typename Type> + class AnaToolPropertyPublicTool : public AnaToolProperty + { + public: + AnaToolPropertyPublicTool (const std::string& val_name, + const AnaToolConfig& val_config) + : m_name (val_name), m_config (val_config) + {} + #ifdef ROOTCORE - template<class T> inline const std::string& - AnaToolHandle<T> :: - type () const noexcept - { -#ifndef NDEBUG - this->testInvariant (); + public: + virtual StatusCode + applyPropertyRootCore (AsgTool& tool, const std::string& name, + AnaToolCleanup& cleanup) + const override + { + using namespace msgToolHandle; + std::shared_ptr<AnaToolShare> share; + ANA_CHECK (AnaToolShareList::singleton().makeShare + (m_name, m_config, share)); + cleanup.addCleanup (share); + ToolHandle<Type> myth; + ANA_CHECK (toolHandleCast (myth, share->th())); + ANA_CHECK (tool.setProperty (name, myth)); + return StatusCode::SUCCESS; + } #endif - return m_handle->type(); - } - template<class T> inline const std::string& - AnaToolHandle<T> :: - name () const noexcept - { -#ifndef NDEBUG - this->testInvariant (); -#endif - return m_handle->name(); - } -#else - template<class T> inline std::string - AnaToolHandle<T> :: - type () const - { -#ifndef NDEBUG - this->testInvariant (); +#ifndef ROOTCORE + private: + virtual StatusCode + applyPropertyAthena (const std::string& toolName, + const std::string& name, + AnaToolCleanup& cleanup) + const override + { + using namespace msgToolHandle; + std::shared_ptr<AnaToolShare> share; + ANA_CHECK (AnaToolShareList::singleton().makeShare + (m_name, m_config, share)); + cleanup.addCleanup (share); + + ToolHandle<Type> th; + ANA_CHECK (toolHandleCast (th, share->th())); + + // this is so we clear out properties from catalogue when tool + // is destroyed. DISABLED: we no longer clear out tools after + // we are done with them + // std::shared_ptr<PropertyValueManager> manager + // (new PropertyValueManager (th.name(), name)); + // cleanup.addCleanup (manager); + + // for athena we hand our property to the joboptions svc + ANA_CHECK (detail::addPropertyToCatalogue (toolName, name, th.typeAndName())); + // manager->m_cleanup = true; + return StatusCode::SUCCESS; + } #endif - return m_handle->type(); - } - template<class T> inline std::string - AnaToolHandle<T> :: - name () const - { -#ifndef NDEBUG - this->testInvariant (); -#endif - return m_handle->name(); - } -#endif + private: + std::string m_name; + AnaToolConfig m_config; + }; + - template<class T> StatusCode - AnaToolHandle<T> :: - make (const std::string& val_type) - { - using namespace msgToolHandle; -#ifndef NDEBUG - this->testInvariant (); -#endif - ANA_CHECK (preMake (val_type)); - if (m_state != State::BEGIN) +#ifdef ROOTCORE + template<typename Type> void AnaToolConfig :: + registerNew () { -#ifndef NDEBUG - this->testInvariant (); + m_factory = [] (AsgTool*& tool, const std::string& name) -> StatusCode { + tool = new Type (name); return StatusCode::SUCCESS;}; + } #endif + + + +#ifdef ROOTCORE + template<typename Type> StatusCode AnaToolConfig :: + setProperty (const std::string& val_name, const Type& val_value) + { + std::shared_ptr<detail::AnaToolProperty> anaProperty + (new detail::AnaToolPropertyValueRootCore<Type> (val_value)); + addProperty (val_name, anaProperty); return StatusCode::SUCCESS; } - return doMake (); - } +#else + template<typename Type> StatusCode AnaToolConfig :: + setProperty (const std::string& val_name, const Type& val_value) + { + using namespace msgToolHandle; + std::shared_ptr<detail::AnaToolProperty> anaProperty + (new detail::AnaToolPropertyValueAthena (val_value)); + addProperty (val_name, anaProperty); + return StatusCode::SUCCESS; + } +#endif - template <class T> - StatusCode AnaToolHandle<T> :: - make () - { - using namespace msgToolHandle; -#ifndef NDEBUG - this->testInvariant (); + template<typename Type> StatusCode AnaToolConfig :: + setProperty (const std::string& val_name, + const AnaToolHandle<Type>& val_value) + { + using namespace msgToolHandle; + + // once initialized the AnaToolHandle is not that different from + // a regular ToolHandle and we just use it as such + if (val_value.isInitialized()) + return setProperty (val_name, val_value.getHandle()); + + switch (val_value.mode()) + { + case AnaToolHandleMode::EMPTY: + return setProperty (val_name, ToolHandle<Type> ()); + case AnaToolHandleMode::CREATE_PRIVATE: + { + std::shared_ptr<AnaToolPropertyPrivateTool<Type> > anaProperty + (new AnaToolPropertyPrivateTool<Type> (val_value.config())); + addProperty (val_name, anaProperty); + } + return StatusCode::SUCCESS; + case AnaToolHandleMode::CREATE_SHARED: + case AnaToolHandleMode::RETRIEVE_SHARED: + { + std::shared_ptr<AnaToolPropertyPublicTool<Type> > anaProperty + (new AnaToolPropertyPublicTool<Type> (val_value.name(), val_value.config())); + addProperty (val_name, anaProperty); + } + return StatusCode::SUCCESS; + case AnaToolHandleMode::USER: + return setProperty (val_name, val_value.getHandle()); + } + return StatusCode::FAILURE; //compiler dummy + } + + + +#ifndef ROOTCORE + template<typename Type> StatusCode AnaToolConfig :: + setProperty (const std::string& val_name, + const ToolHandle<Type>& val_value) + { + using namespace msgToolHandle; + + //strip the parent name + if (val_value.empty()) + return setProperty (val_name, std::string ()); + else if (val_value.isPublic()) + { + return setProperty (val_name, + val_value.type() + "/" + val_value.name()); + } else + { + std::shared_ptr<AnaToolPropertyCopyTool> shared + (new AnaToolPropertyCopyTool + (val_value.type(), val_value.parentName() + "." + val_value.name())); + addProperty (val_name, shared); + return StatusCode::SUCCESS; + } + } + + + + template<typename Type> StatusCode AnaToolConfig :: + setProperty (const std::string& val_name, + const ToolHandleArray<Type>& val_value) + { + using namespace msgToolHandle; + + std::vector<std::string> tools; + // loop over toolhandles in array, strip off any parent naming + // and set property with the result + for (auto& toolHandle : val_value) + { + if (toolHandle.empty()) + { + ANA_MSG_ERROR ("trying to initialize ToolHandleArray property " << val_name << " with empty handle"); + return StatusCode::FAILURE; + } + + //strip the parent name + std::string tool_name = toolHandle.name(); + tools.push_back (toolHandle.type() + "/" + tool_name); + } + + return setProperty (val_name, tools); + } #endif - ANA_CHECK (preMake ("")); - if (m_state != State::BEGIN) + + + + template<typename ToolType> StatusCode AnaToolConfig :: + makeTool (const std::string& name, + parentType_t *parent, + ToolHandle<ToolType>& th, + AnaToolCleanup& cleanup) const { -#ifndef NDEBUG - this->testInvariant (); + using namespace msgUserCode; + ToolHandle<interfaceType_t> baseTH; + AnaToolCleanup baseCleanup; + ANA_CHECK (makeBaseTool (name, parent, baseTH, baseCleanup)); + ANA_CHECK (toolHandleCast (th, baseTH)); + cleanup.swap (baseCleanup); +#ifndef ROOTCORE + baseTH->release (); #endif return StatusCode::SUCCESS; } - if (type().empty()) - { - ANA_MSG_ERROR ("called AnaToolHandle::make() without a type"); - ANA_MSG_ERROR ("you can either pass it into make() directly,"); - ANA_MSG_ERROR ("or as part of the name to the constructor"); - ANA_MSG_ERROR ("(format type/name for the constructor)"); - return StatusCode::FAILURE; - } + } + + + + template <typename T> + std::ostream& operator << (std::ostream& str, const AnaToolHandle<T>& obj) + { + return str << obj.getHandle(); + } + + + + template<class T> void AnaToolHandle<T> :: + testInvariant () const + { +#define CHECK_INVARIANT(x) \ + if (!(x)) { std::cerr << __FILE__ << ":" << __LINE__ << ": invariant violated: " << #x << std::endl; std::abort(); } + + // General requirements + CHECK_INVARIANT (&*this != nullptr); + CHECK_INVARIANT (m_handleUser != nullptr); + // CHECK_INVARIANT (m_parentPtr == nullptr || m_parentPtr->name() == m_parentName); + // #ifndef ROOTCORE + // CHECK_INVARIANT (m_parentPtr == m_handleUser->parent()); + // #endif - return doMake (); +#undef CHECK_INVARIANT } - template <class T> template <class T2> - StatusCode AnaToolHandle<T> :: - setProperty (const std::string& property, const T2& value) + template<class T> AnaToolHandle<T> :: + AnaToolHandle (const std::string& val_name, parentType_t *val_parent) + : m_parentName (val_parent ? val_parent->name() : std::string()), + m_parentPtr (val_parent), + m_handleUser (new ToolHandle<T> (val_name, val_parent)), + m_originalTypeAndName (m_handleUser->typeAndName ()), + m_allowEmpty (val_name.empty()) { - using namespace msgToolHandle; + setTypeAndName (val_name); #ifndef NDEBUG this->testInvariant (); #endif - ANA_CHECK (preSetProperty (property)); - if (m_state != State::CREATED && m_state != State::BAD_PROPERTY) + } + + + + template<class T> AnaToolHandle<T> :: + AnaToolHandle (AnaToolHandle<T>&& that) + : AnaToolHandle () + { + swap (that); + } + + + + template<class T> AnaToolHandle<T> :: + AnaToolHandle (const AnaToolHandle<T>& that) + : m_config (that.m_config), + m_name (that.m_name), + m_parentName (that.m_parentName), + m_parentPtr (that.m_parentPtr), + m_handleUser (new ToolHandle<T> (*that.m_handleUser)), + m_originalTypeAndName (that.m_originalTypeAndName), + m_isInitialized (that.m_isInitialized.load()), + m_allowEmpty (that.m_allowEmpty) + { + if (m_isInitialized.load()) { -#ifndef NDEBUG - testInvariant (); -#endif - return StatusCode::SUCCESS; + m_toolPtr = that.m_toolPtr; + m_mode = that.m_mode; + m_cleanup = that.m_cleanup; } -#ifdef ROOTCORE +#ifndef ROOTCORE + if (!m_handleUser->empty()) + (*m_handleUser)->release(); +#endif - // Call setProperty on our cached tool pointer - if (m_toolConfig->setProperty (property, value).isFailure()) - m_state = State::BAD_PROPERTY; #ifndef NDEBUG + that.testInvariant (); testInvariant (); #endif - return StatusCode::SUCCESS; + } -#else - m_addedProperties.push_back(property); //this is so we clear out properties from catalogue when tool is destroyed - //for athena we hand our property to the joboptions svc - const std::string val = Gaudi::Utils::toString ( value ) ; - return detail::addPropertyToCatalogue( fullName() , property, val ); -#endif + template<class T> AnaToolHandle<T>& AnaToolHandle<T> :: + operator = (const AnaToolHandle<T>& that) + { + // no invariant used + AnaToolHandle<T> (that).swap (*this); + return *this; } - template <class T> template <class T2> - StatusCode AnaToolHandle<T> :: - setProperty (const std::string& property, const ToolHandle<T2>& toolHandle) + template<class T> void AnaToolHandle<T> :: + swap (AnaToolHandle<T>& that) noexcept { - using namespace msgToolHandle; #ifndef NDEBUG - this->testInvariant (); + testInvariant (); + that.testInvariant (); #endif - if (toolHandle.empty()) + m_cleanup.swap (that.m_cleanup); + m_config.swap (that.m_config); + m_name.swap (that.m_name); + m_parentName.swap (that.m_parentName); + std::swap (m_parentPtr, that.m_parentPtr); { - ANA_MSG_ERROR ("trying to initialize ToolHandle property " << property << " with empty handle"); -#ifndef NDEBUG - testInvariant (); + ToolHandle<T> tmp = *m_handleUser; +#ifndef ROOTCORE + if (!tmp.empty()) + tmp->release(); #endif - return StatusCode::FAILURE; + *m_handleUser = *that.m_handleUser; + *that.m_handleUser = tmp; } - - ANA_CHECK (preSetProperty (property)); - if (m_state != State::CREATED && m_state != State::BAD_PROPERTY) + m_originalTypeAndName.swap (that.m_originalTypeAndName); { -#ifndef NDEBUG - testInvariant (); -#endif - return StatusCode::SUCCESS; + const auto tmp = m_isInitialized.load(); + m_isInitialized = that.m_isInitialized.load(); + that.m_isInitialized = tmp; } + std::swap (m_toolPtr, that.m_toolPtr); + std::swap (m_mode, that.m_mode); + std::swap (m_allowEmpty, that.m_allowEmpty); -#ifdef ROOTCORE - - // Call setProperty on our cached tool pointer - if (m_toolConfig->setProperty (property, toolHandle).isFailure()) - m_state = State::BAD_PROPERTY; #ifndef NDEBUG testInvariant (); + that.testInvariant (); #endif - return StatusCode::SUCCESS; - - /* - // Call setProperty on our cached tool pointer. - // This only works in RootCore because the tool pointer constructor - // form doesn't exist in Athena. - return m_toolConfig->setProperty (property, &*toolHandle); - */ - -#else + } - auto tool = toolHandle.get(); - //tool must already exist in the ToolSvc - if(tool==nullptr) { - ANA_MSG_ERROR("Tool " << toolHandle.typeAndName() << " must be initialized before you can pass it to another tool with setProperty"); - return StatusCode::FAILURE; - } - //strip the parent name - std::string tool_name = toolHandle.name(); - if(tool_name.find(name()+".")==0) { - //we also strip the name of our tool, if it appears at the front of tool_name ... - //this is so private subtools can be set with code like: - //ATH<> subtool("MyTool/ParentTool.SubTool"); - //ATH<> parenttool("MyTool2/ParentTool"); - //parenttool.setProperty("SubToolProperty",subtool); - tool_name.replace(0,name().size()+1,""); - } - - return setProperty( property, tool->type() + "/" + tool_name ); -#endif + template<class T> AnaToolHandle<T>& AnaToolHandle<T> :: + operator = (AnaToolHandle<T>&& that) + { + // no invariant used + swap (that); + return *this; } -#ifndef ROOTCORE - -template <class T> template <class T2> - StatusCode AnaToolHandle<T> :: - setProperty (const std::string& property, const ToolHandleArray<T2>& toolHandleArray) + template<class T> AnaToolHandle<T> :: + ~AnaToolHandle () noexcept { using namespace msgToolHandle; #ifndef NDEBUG this->testInvariant (); #endif + } - - ANA_CHECK (preSetProperty (property)); - if (m_state != State::CREATED && m_state != State::BAD_PROPERTY) - { + template<class T> bool + AnaToolHandle<T> :: + empty () const + { #ifndef NDEBUG - testInvariant (); + this->testInvariant (); #endif - return StatusCode::SUCCESS; + switch (getMode()) + { + case detail::AnaToolHandleMode::EMPTY: + return true; + case detail::AnaToolHandleMode::CREATE_PRIVATE: + case detail::AnaToolHandleMode::CREATE_SHARED: + case detail::AnaToolHandleMode::RETRIEVE_SHARED: + return false; + case detail::AnaToolHandleMode::USER: + return m_handleUser->empty(); } + return false; //compiler dummy + } - std::vector<std::string> tools; - //loop over toolhandles in array, strip off any parent naming and set property with the result - for(auto& toolHandle : toolHandleArray) { - if (toolHandle.empty()) - { - ANA_MSG_ERROR ("trying to initialize ToolHandle property " << property << " with empty handle"); - #ifndef NDEBUG - testInvariant (); - #endif - return StatusCode::FAILURE; - } - auto tool = toolHandle.get(); - if(tool == nullptr) { - ANA_MSG_ERROR("Tool " << toolHandle.typeAndName() << " must be initialized before you can pass it to another tool with setProperty"); - return StatusCode::FAILURE; - } - - //strip the parent name - std::string tool_name = toolHandle.name(); - if(tool_name.find(name()+".")==0) { - //we also strip the name of our tool, if it appears at the front of tool_name ... - //this is so private subtools can be set with code like: - //ATH<> subtool("MyTool/ParentTool.SubTool"); - //ATH<> parenttool("MyTool2/ParentTool"); - //parenttool.setProperty("SubToolProperty",subtool); - tool_name.replace(0,name().size()+1,""); - } - - tools.push_back( tool->type() + "/" + tool_name ); - - } - return setProperty( property, tools ); + template<class T> inline bool AnaToolHandle<T> :: + isPublic () const noexcept + { +#ifndef NDEBUG + this->testInvariant (); +#endif + return m_parentName.empty(); } + + + template<class T> inline const std::string& AnaToolHandle<T> :: + type () const noexcept + { +#ifndef NDEBUG + this->testInvariant (); +#endif + return m_config.type(); + } + + + + template<class T> inline const std::string& + AnaToolHandle<T> :: + name () const noexcept + { +#ifndef NDEBUG + this->testInvariant (); #endif + return m_name; + } + template <class T> template <class T2> StatusCode AnaToolHandle<T> :: - setProperty (const std::string& property, const AnaToolHandle<T2>& toolHandle) + setProperty (const std::string& property, const T2& value) { using namespace msgToolHandle; - // no invariant used - if (!toolHandle.isInitialized()) +#ifndef NDEBUG + this->testInvariant (); + if (isInitialized()) { - ANA_MSG_ERROR ("need to pass initialized tool handle into setProperty"); - return StatusCode::FAILURE; + ANA_MSG_FATAL ("AnaToolHandle has already been initialized: " << *this); + std::abort(); } - -#ifdef ROOTCORE - return setProperty (property, ToolHandle<T2> (toolHandle.get())); -#else - return setProperty (property, toolHandle.getHandle()); #endif + + return m_config.setProperty (property, value); } @@ -508,72 +797,66 @@ template <class T> template <class T2> { using namespace msgToolHandle; + // ensure we don't initialize twice concurrently + std::lock_guard<std::recursive_mutex> lock (m_initializeMutex); + #ifndef NDEBUG this->testInvariant (); -#endif - switch (m_state) + if (isInitialized()) { - case State::BEGIN: - // make the tool, this can cause our state to switch to - // PREINITIALIZED, if the tool we are setup to make is actually - // coming from user config or is shared - ANA_CHECK (make()); - assert (m_state != State::BEGIN); - return initialize (); - case State::PREINITIALIZED: - // we are using a tool that already has already been - // initialized, so all we need to do is change state - m_state = State::INITIALIZED; -#ifndef NDEBUG - this->testInvariant (); -#endif - return StatusCode::SUCCESS; - case State::CREATED: - // ok, tool created but not initialized, can initialize - break; - case State::INITIALIZED: - ANA_MSG_ERROR ("tool " << *this << " has already been initialized"); - std::abort (); - case State::BAD_PROPERTY: - ANA_MSG_ERROR ("encountered error setting properties on " << *this << " refusing to initialize"); - m_state = State::BROKEN; - return StatusCode::FAILURE; - case State::BROKEN: - ANA_MSG_ERROR ("tool handle " << *this << " in broken state"); - return StatusCode::FAILURE; + ANA_MSG_FATAL ("AnaToolHandle has already been initialized: " << *this); + std::abort(); } +#endif - // first setting state to broken, so if we fail it stays broken - m_state = State::BROKEN; - - -#ifdef ROOTCORE + std::shared_ptr<detail::AnaToolShare> sharedTool; + const detail::AnaToolHandleMode mode = getMode (sharedTool); - ANA_CHECK (m_toolPtr->initialize()); + ToolHandle<T> th; + detail::AnaToolCleanup cleanup; - if (m_parent == nullptr) + switch (mode) { - auto& pointer = sharedToolPointer (); - assert (pointer.lock() == nullptr); - pointer = m_toolOwn; - assert (sharedToolPointer ().lock() == m_toolOwn); + case detail::AnaToolHandleMode::EMPTY: + break; + case detail::AnaToolHandleMode::CREATE_PRIVATE: + ANA_CHECK (m_config.makeTool (m_name, m_parentPtr, th, cleanup)); + break; + case detail::AnaToolHandleMode::CREATE_SHARED: + ANA_CHECK (detail::AnaToolShareList::singleton().makeShare (m_name, m_config, sharedTool)); + // no break + case detail::AnaToolHandleMode::RETRIEVE_SHARED: + assert (sharedTool != nullptr); + ANA_CHECK (detail::toolHandleCast (th, sharedTool->th())); +#ifndef ROOTCORE + if (!th.empty()) + th->release (); +#endif + cleanup.addCleanup (sharedTool); + break; + case detail::AnaToolHandleMode::USER: + th = *m_handleUser; + if (th.empty() && !m_allowEmpty) + { + ANA_MSG_ERROR ("user configured an empty handle for a non-empty AnaToolHandle: " << *this); + return StatusCode::FAILURE; + } + break; } -#else - - //in athena, before retrieving, we inspect the joboptionssvc for properties matching my property name, and copies those over - ANA_CHECK( detail::copyPropertiesInCatalogue( m_handle->parentName() + "." + name() , fullName() ) ); - - //just 'retrieve' the toolhandle .. if fails, then go broken - ANA_CHECK (m_handle->retrieve()); - - //must increment refcount on the tool (get two refcounts automatically, one for ToolSvc, and *i think* one for HistorySvc (yuck) - //(*m_handle)->addRef(); - m_toolPtr = &**m_handle; + T *toolPtr = nullptr; + ANA_CHECK (makeToolRetrieve (toolPtr, th)); + *m_handleUser = th; +#ifndef ROOTCORE + if (!th.empty()) + th->release (); #endif + m_mode = mode; + m_cleanup.swap (cleanup); + m_toolPtr = toolPtr; + m_isInitialized = true; - m_state = State::INITIALIZED; #ifndef NDEBUG this->testInvariant (); #endif @@ -599,41 +882,69 @@ template <class T> template <class T2> #ifndef NDEBUG this->testInvariant (); #endif - return // !empty() && -#ifdef ROOTCORE - // !(m_parent == nullptr && sharedToolPointer().lock() != nullptr) && - // !(m_parent == nullptr && !name().empty() && ToolStore::contains<T> (name())) && + switch (getMode()) + { + case detail::AnaToolHandleMode::EMPTY: + case detail::AnaToolHandleMode::CREATE_PRIVATE: + case detail::AnaToolHandleMode::CREATE_SHARED: + return true; + case detail::AnaToolHandleMode::RETRIEVE_SHARED: + case detail::AnaToolHandleMode::USER: + return false; + } + return true; //compiler dummy + } + + + + template<class T> +#ifndef NDEBUG + inline #endif - !isUserConfigured (); + bool AnaToolHandle<T> :: + isInitialized () const noexcept + { +#ifndef NDEBUG + this->testInvariant (); +#endif + return m_isInitialized; + } + + + + template<class T> inline T * + AnaToolHandle<T> :: + operator -> () + { + // no invariant used + return get (); } - template<class T> bool + template<class T> inline const T * AnaToolHandle<T> :: - isInitialized () const noexcept + operator -> () const { -#ifndef NDEBUG - this->testInvariant (); -#endif - return (m_state == State::INITIALIZED); + // no invariant used + return get (); } - template<class T> inline T * + template<class T> inline T& AnaToolHandle<T> :: - operator -> () const noexcept + operator * () { // no invariant used - return get (); + return *get (); } - template<class T> inline T& + template<class T> inline const T& AnaToolHandle<T> :: - operator * () const noexcept + operator * () const { // no invariant used return *get (); @@ -643,32 +954,35 @@ template <class T> template <class T2> template<class T> inline T* AnaToolHandle<T> :: - get () const noexcept + get () { using namespace msgToolHandle; #ifndef NDEBUG this->testInvariant (); #endif - switch (m_state) - { - case State::BEGIN: - case State::PREINITIALIZED: - case State::CREATED: - case State::BAD_PROPERTY: - ANA_MSG_FATAL ("can't call get on handle " << *this << " without initialized tool"); - std::abort(); - case State::INITIALIZED: - break; - case State::BROKEN: - ANA_MSG_FATAL ("can't call get on handle " << *this << " which is in a broken state"); - std::abort(); - } + + if (m_isInitialized.load()) + return m_toolPtr; + + std::lock_guard<std::recursive_mutex> lock (m_initializeMutex); + if (!m_isInitialized) + ANA_CHECK_THROW (initialize()); + assert (m_isInitialized); return m_toolPtr; } + template<class T> inline const T* + AnaToolHandle<T> :: + get () const + { + return const_cast<AnaToolHandle<T>*>(this)->get(); + } + + + template <class T> template<typename T2> void AnaToolHandle<T> :: declarePropertyFor (T2 *tool, const std::string& name, @@ -677,489 +991,348 @@ template <class T> template <class T2> using namespace msgToolHandle; #ifndef NDEBUG this->testInvariant (); -#endif - switch (m_state) + if (isInitialized()) { - case State::BEGIN: - break; - case State::PREINITIALIZED: - case State::CREATED: - case State::INITIALIZED: - case State::BAD_PROPERTY: - case State::BROKEN: ANA_MSG_FATAL ("can't declare tool handle " << *this << " as property " << name << " after tool has been instantiated"); std::abort (); } +#endif - if (m_parent != nullptr && m_parent != tool) + if (m_parentPtr != nullptr && m_parentPtr != tool) { - ANA_MSG_FATAL ("can't declare tool handle " << *this << " as property for tool " << tool->name() << " as it has a different parent tool " << m_parent->name()); + ANA_MSG_FATAL ("can't declare tool handle " << *this << " as property for tool " << tool->name() << " as it has a different parent tool " << m_parentPtr->name()); std::abort (); } - ANA_CHECK_THROW (tool->declareProperty (name, *m_handle, description)); + ANA_CHECK_THROW (tool->declareProperty (name, *m_handleUser, description)); } - template <class T> bool - AnaToolHandle<T> :: - inPremakeState () const noexcept - { -#ifndef NDEBUG - this->testInvariant (); -#endif - switch (m_state) - { - case State::BEGIN: - return true; - case State::PREINITIALIZED: - case State::CREATED: - case State::INITIALIZED: - case State::BAD_PROPERTY: - case State::BROKEN: - return false; - } - return false; //compiler dummy - } - template <class T> bool + template <class T> const ToolHandle<T>& AnaToolHandle<T> :: - inBrokenState () const noexcept + getHandle () const noexcept { #ifndef NDEBUG this->testInvariant (); #endif - switch (m_state) - { - case State::BROKEN: - return true; - case State::BEGIN: - case State::PREINITIALIZED: - case State::CREATED: - case State::INITIALIZED: - case State::BAD_PROPERTY: - return false; - } - return false; //compiler dummy + return *m_handleUser; } - template <class T> const ToolHandle<T>& - AnaToolHandle<T> :: - getHandle () const noexcept +#ifdef ROOTCORE + template <class T> template <class T2> void AnaToolHandle<T> :: + setTypeRegisterNew (std::string val_type) { -#ifndef NDEBUG - this->testInvariant (); -#endif - return *m_handle; + using namespace msgToolHandle; + + m_config.registerNew<T2> (); + setType (std::move (val_type)); } +#endif - template <class T> ToolHandle<T>& + template <class T> bool AnaToolHandle<T> :: - handle () + isUserConfigured () const noexcept { + using namespace msgToolHandle; #ifndef NDEBUG this->testInvariant (); #endif - return *m_handle; + + switch (getMode()) + { + case detail::AnaToolHandleMode::EMPTY: + case detail::AnaToolHandleMode::CREATE_PRIVATE: + case detail::AnaToolHandleMode::CREATE_SHARED: + return false; + case detail::AnaToolHandleMode::RETRIEVE_SHARED: + case detail::AnaToolHandleMode::USER: + return true; + } + return false; //compiler dummy } -#ifdef ROOTCORE - template <class T> template <class T2> StatusCode + template<class T> std::string AnaToolHandle<T> :: - makeNew (std::string val_type) + fullName () const { - using namespace msgToolHandle; - - ANA_CHECK (preMake (val_type)); - if (m_state != State::BEGIN) - { #ifndef NDEBUG - this->testInvariant (); + this->testInvariant (); #endif - return StatusCode::SUCCESS; - } - - // Create the tool +#ifndef ROOTCORE + return m_handleUser->parentName() + "." + name(); +#else std::string toolName; - if (m_parent != nullptr) - toolName = m_parent->name() + "." + name(); + if (!isPublic()) + toolName = m_parentName + "." + name(); else toolName = name(); - std::unique_ptr<T2> tool (new T2 (toolName)); - m_toolConfig = tool.get(); - m_toolOwn = std::move (tool); - m_toolPtr = m_toolOwn.get(); - - // Inherit verbosity from parent - if (m_parent != nullptr) - m_toolConfig->msg().setLevel( m_parent->msg().level() ); - - setType (std::move (val_type)); - m_state = State::CREATED; -#ifndef NDEBUG - this->testInvariant (); + return toolName; #endif - return StatusCode::SUCCESS; } -#endif - template <class T> bool - AnaToolHandle<T> :: - isUserConfigured () const noexcept + template<class T> detail::AnaToolHandleMode AnaToolHandle<T> :: + getMode (std::shared_ptr<detail::AnaToolShare>& sharedTool) const { + using namespace msgToolHandle; #ifndef NDEBUG this->testInvariant (); #endif - // we should have cached the value of \ref isUserConfigured in - // \ref make, so we shouldn't try again to check it, as the - // actions in \ref make may actually change the result of \ref - // isUserConfigured - if (m_state != State::BEGIN) - return m_isUserConfigured; + assert (!m_isInitialized); - if (m_handle->isSet()) - return true; + if (m_handleUser->isSet()) + return detail::AnaToolHandleMode::USER; - if (m_handle->typeAndName() != m_originalTypeAndName) - return true; + if (m_handleUser->typeAndName() != m_originalTypeAndName) + return detail::AnaToolHandleMode::USER; #ifdef ROOTCORE - if (m_parent != nullptr) + if (!m_parentName.empty()) { - if (m_handle->parentName() != m_parent->name()) - return true; + if (m_handleUser->parentName() != m_parentName) + return detail::AnaToolHandleMode::USER; } else { - if (m_handle->parentName() != "ToolSvc") - return true; - if (!name().empty()) - { - if (ToolStore::contains<T> (name())) - return true; - if (sharedToolPointer().lock() != nullptr) - return true; - } + if (m_handleUser->parentName() != "ToolSvc") + return detail::AnaToolHandleMode::USER; } #endif + if (isPublic()) + { + if ((sharedTool = detail::AnaToolShareList::singleton() + .getShare (fullName()))) + return detail::AnaToolHandleMode::RETRIEVE_SHARED; +#ifdef ROOTCORE + /// \todo check whether this is actually what we want to do + if (ToolStore::contains<T> (m_handleUser->name())) + return detail::AnaToolHandleMode::USER; +#endif + } + #ifndef ROOTCORE //for athena, all we do here is check if the tool already exists interfaceType_t *tool = nullptr; if( detail::toolExists( fullName(), tool ) ) - return true; + return detail::AnaToolHandleMode::USER; if (detail::hasPropertiesInCatalogue (fullName())) - return true; + return detail::AnaToolHandleMode::USER; #endif - return false; - /* + if (m_config.empty() && m_name.empty()) + return detail::AnaToolHandleMode::EMPTY; - if (m_handle == nullptr) - return false; -#ifdef ROOTCORE - return !m_handle->empty(); -#else - //here we exploit quirk that users who set our handle from another handle - // will get a typeName with the words 'PublicToolHandle' or 'PrivateToolHandle' - // at the start of the typeAndName, so we can detect it that way - if ( - (strncmp(m_handle->typeAndName().c_str(), "PublicToolHandle", strlen("PublicToolHandle")) == 0) || - (strncmp(m_handle->typeAndName().c_str(), "PrivateToolHandle", strlen("PrivateToolHandle")) == 0) - ) return true; - //must also check the joboptions service for properties - ServiceHandle<IJobOptionsSvc> svc("JobOptionsSvc","AnaToolHandle"); - if( svc.retrieve().isFailure() ) return false; - if( svc->getProperties(m_handle->parentName() + "." + m_handle->name()) ) return true; - svc.release().ignore(); - return false; + if (isPublic()) + return detail::AnaToolHandleMode::CREATE_SHARED; + else + return detail::AnaToolHandleMode::CREATE_PRIVATE; -#endif + /// \todo check whether we still need any of this code to determin + /// if a tool handle is empty + /* + //handle is empty if: it wasn't user configured and our type and name are not set, or it is user configured and the member handle is empty + return( ( isUserConfigured() && ( m_handleUser->empty() || m_handleUser->typeAndName()=="PublicToolHandle('')" || m_handleUser->typeAndName()=="PrivateToolHandle('')" ) ) + || ( (!isUserConfigured() && type()=="" && name()=="") ) ); */ } - template <class T> StatusCode - AnaToolHandle<T> :: - preSetProperty (const std::string& property) + + template<class T> detail::AnaToolHandleMode AnaToolHandle<T> :: + getMode () const { - using namespace msgToolHandle; + if (m_isInitialized) + return m_mode; + + std::shared_ptr<detail::AnaToolShare> sharedTool; + return getMode (sharedTool); + } + + + template<class T> std::string AnaToolHandle<T> :: + typeAndName () const + { #ifndef NDEBUG this->testInvariant (); #endif - switch (m_state) - { - case State::BEGIN: - ANA_CHECK (make()); - return preSetProperty (property); - case State::PREINITIALIZED: - // we are using a tool that already has all its properties set - // and initialized, so we are not doing that again - ANA_MSG_INFO ("Ignoring setProperty for " << *this << "." << property << " - tool preInitialized"); - return StatusCode::SUCCESS; - case State::CREATED: - case State::BAD_PROPERTY: - // ok, tool created but not initialized, can set properties - return StatusCode::SUCCESS; - case State::INITIALIZED: - ANA_MSG_FATAL ("tool " << *this << " has already been initialized"); - std::abort (); - case State::BROKEN: - ANA_MSG_ERROR ("tool handle " << *this << " in broken state"); - return StatusCode::FAILURE; - } - return StatusCode::FAILURE; //compiler dummy + if (name().empty()) + return m_config.type(); + if (m_config.type().empty()) + return name(); + return m_config.type() + "/" + name(); } - template <class T> StatusCode - AnaToolHandle<T> :: - preMake (const std::string& val_type) + template<class T> void AnaToolHandle<T> :: + setType (std::string val_type) noexcept { using namespace msgToolHandle; - #ifndef NDEBUG this->testInvariant (); -#endif - - switch (m_state) + if (isInitialized()) { - case State::BEGIN: - break; - case State::PREINITIALIZED: - case State::CREATED: - case State::INITIALIZED: - case State::BAD_PROPERTY: - ANA_MSG_FATAL ("tool " << *this << " has already been made, can't call make again"); - std::abort (); - case State::BROKEN: - ANA_MSG_ERROR ("tool handle " << *this << " in broken state"); - return StatusCode::FAILURE; - } - -#ifdef ROOTCORE - // this ensures that in RootCore we can share public tools when - // requested with the same name - if (m_parent == nullptr && m_handle->isSet() == false && - !name().empty()) - { - m_isUserConfigured = true; - m_toolOwn = sharedToolPointer().lock(); - m_toolPtr = m_toolOwn.get(); - if (m_toolPtr != nullptr) - { - // this is right: PREINITIALIZED means that we rely on a tool - // that has already been initialized by somebody else (another - // ToolHandle in this case). - m_state = State::PREINITIALIZED; -#ifndef NDEBUG - this->testInvariant (); -#endif - return StatusCode::SUCCESS; - } + ANA_MSG_FATAL ("AnaToolHandle has already been initialized: " << *this); + std::abort(); } #endif + m_config.setType (std::move (val_type)); + } - if ((m_isUserConfigured = isUserConfigured())) - { - m_state = State::BROKEN; - try - { - m_toolPtr = &**m_handle; - if (m_toolPtr == nullptr) - { - ANA_MSG_ERROR ("failed to retrieve tool from tool handle " << *m_handle); - return StatusCode::FAILURE; - } - } catch (std::exception& e) - { - ANA_MSG_ERROR ("encountered exception during tool retrieval (" << - *m_handle << "): " << e.what()); - return StatusCode::FAILURE; - } - m_state = State::PREINITIALIZED; -#ifndef NDEBUG - testInvariant (); -#endif - return StatusCode::SUCCESS; - } - - if (!val_type.empty()) - { - if (val_type.find ('/') != std::string::npos) - setTypeAndName (val_type); - else - setType (val_type); - } - if (type().empty()) - { - ANA_MSG_ERROR ("no type specified for ToolHandle"); - return StatusCode::FAILURE; - } - if (name().empty()) + template<class T> void AnaToolHandle<T> :: + setName (std::string val_name) noexcept + { + using namespace msgToolHandle; +#ifndef NDEBUG + this->testInvariant (); + if (isInitialized()) { - ANA_MSG_ERROR ("no name specified for ToolHandle"); - return StatusCode::FAILURE; + ANA_MSG_FATAL ("AnaToolHandle has already been initialized: " << *this); + std::abort(); } - - return StatusCode::SUCCESS; - - /* -#ifndef ROOTCORE - //check form of typeAndName ... if it is "PublicToolHandle('AAA/BBB')" then we need to parse it - std::string mytype = m_handle->typeAndName(); - if(strncmp(mytype.c_str(), "PublicToolHandle(", strlen("PublicToolHandle(")) == 0) { - mytype.replace(0,18,""); mytype.replace(strlen(mytype.c_str())-2,2,""); - /// \todo check against original implementation - *m_handle = ToolHandle<T>(mytype, 0); //turn our handle public! - } else if(strncmp(mytype.c_str(), "PrivateToolHandle(", strlen("PrivateToolHandle(")) == 0) { - mytype.replace(0,19,""); mytype.replace(strlen(mytype.c_str())-2,2,""); - /// \todo check against original implementation - *m_handle = ToolHandle<T>(mytype, m_parent); - } else if(strncmp(mytype.c_str(), "PublicToolHandleHack(", strlen("PublicToolHandleHack(")) == 0) { //hack case for when setPropertyToolHandle has been used - mytype.replace(0,22,""); mytype.replace(strlen(mytype.c_str())-2,2,""); - ///we don't replace the toolhandle because we need the original 'hacked' toolhandle - } #endif -#ifndef ROOTCORE - //for athena, all we do here is check if the tool already exists, marking it preinitialized if so -interfaceType_t* tool(0); -if( detail::toolExists( fullName(), tool ) ) { -//verify the tool is correct type -if(tool->type() != m_handle->type()) { -ANA_MSG_FATAL(" Tool of type " << tool->type() << " called " << tool->name() << " already exists. Cannot create tool with same name of type " << m_handle->type()); + m_name = std::move (val_name); + #ifndef NDEBUG -this->testInvariant (); -#endif -return StatusCode::FAILURE; -} -m_state = State::PREINITIALIZED; -m_toolPtr = &*m_handle; -} + this->testInvariant (); #endif - - */ } -#ifdef ROOTCORE - template<class T> inline std::weak_ptr<T>& AnaToolHandle<T> :: - sharedToolPointer () const + template<class T> void AnaToolHandle<T> :: + setTypeAndName (const std::string& val_typeAndName) { + using namespace msgToolHandle; #ifndef NDEBUG - this->testInvariant (); + if (isInitialized()) + { + ANA_MSG_FATAL ("AnaToolHandle has already been initialized: " << *this); + std::abort(); + } #endif - assert (!name().empty()); - static std::map<std::string,std::weak_ptr<T>> toolMap; - return toolMap[name()]; + auto split = val_typeAndName.find ("/"); + if (split != std::string::npos) + { + setTypeAndName (val_typeAndName.substr (0, split), + val_typeAndName.substr (split+1)); + } else + { + setTypeAndName (val_typeAndName, val_typeAndName); + } } -#endif -#ifndef ROOTCORE - template<class T> std::string - AnaToolHandle<T> :: - fullName () const + template<class T> void AnaToolHandle<T> :: + setTypeAndName (std::string val_type, std::string val_name) noexcept { + using namespace msgToolHandle; #ifndef NDEBUG - this->testInvariant (); + if (isInitialized()) + { + ANA_MSG_FATAL ("AnaToolHandle has already been initialized: " << *this); + std::abort(); + } #endif - return m_handle->parentName() + "." + name(); + setType (std::move (val_type)); + setName (std::move (val_name)); } -#endif - template<class T> StatusCode - AnaToolHandle<T> :: - doMake () + template<class T> StatusCode AnaToolHandle<T> :: + makeToolRetrieve + (T*& toolPtr, ToolHandle<T>& toolHandle) const { using namespace msgToolHandle; -#ifdef ROOTCORE - - // Call the Athena helper function to invoke the tool factory. - AsgTool *toolPtr = nullptr; - - std::string toolName; - if (m_parent != nullptr) - toolName = m_parent->name() + "." + name(); - else - toolName = name(); + if (toolHandle.empty()) + { + toolPtr = nullptr; + return StatusCode::SUCCESS; + } try { - ANA_CHECK (detail::makeToolRootCore (type(), toolName, toolPtr)); + toolPtr = &*toolHandle; + if (toolPtr == nullptr) + { + ANA_MSG_ERROR ("failed to retrieve tool from tool handle " << *m_handleUser); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; } catch (std::exception& e) { - ANA_MSG_ERROR ("encountered exception during tool creation(" << - type() << "," << name() << "): " << e.what()); - m_state = State::BROKEN; -#ifndef NDEBUG - this->testInvariant (); -#endif + ANA_MSG_ERROR ("encountered exception during tool retrieval (" << toolHandle << "): " << e.what()); return StatusCode::FAILURE; } - if (toolPtr == nullptr) - { - ANA_MSG_FATAL ("failed to allocate tool: " + type()); - m_state = State::BROKEN; + } + + + + template<class T> detail::AnaToolHandleMode AnaToolHandle<T> :: + mode () const + { #ifndef NDEBUG - this->testInvariant (); + this->testInvariant (); #endif - return StatusCode::FAILURE; - } + return getMode (); + } - // Try to cast to the requested interface - m_toolOwn.reset (dynamic_cast<T*>(toolPtr)); - m_toolPtr = m_toolOwn.get(); - if (m_toolPtr == nullptr) - { - assert (toolPtr != nullptr); - delete toolPtr; - ANA_MSG_ERROR ("failed to cast tool of type " + type() + " to requested interface"); - m_state = State::BROKEN; + + + template<class T> const detail::AnaToolConfig& AnaToolHandle<T> :: + config () const + { #ifndef NDEBUG - this->testInvariant (); + this->testInvariant (); #endif - return StatusCode::FAILURE; - } - - m_toolConfig = toolPtr; + return m_config; + } - // Inherit verbosity from parent ... in athena this is done by passing the parent in the factory method - if (m_parent != nullptr) - m_toolConfig->msg().setLevel( m_parent->msg().level() ); -#else - //tool doesn't exist, we should also check that we have the factory available for this type - // ANA_CHECK (detail::factoryExists( m_handle->type() )); + template<class T> bool AnaToolHandle<T> :: + allowEmpty () const noexcept + { +#ifndef NDEBUG + this->testInvariant (); #endif + return m_allowEmpty; + } + - m_state = State::CREATED; + + template<class T> void AnaToolHandle<T> :: + setAllowEmpty (bool val_allowEmpty) noexcept + { + using namespace msgToolHandle; #ifndef NDEBUG this->testInvariant (); + if (isInitialized()) + { + ANA_MSG_FATAL ("AnaToolHandle has already been initialized: " << *this); + std::abort(); + } #endif - return StatusCode::SUCCESS; + m_allowEmpty = val_allowEmpty; } } diff --git a/Control/AthToolSupport/AsgTools/AsgTools/AsgMetadataTool.h b/Control/AthToolSupport/AsgTools/AsgTools/AsgMetadataTool.h index 4485e6ff8aebdd2a3b6498d8935d37d0f14b4ae4..548cdfa5d2d3a85ce433022699536f4d1e0bcfc0 100644 --- a/Control/AthToolSupport/AsgTools/AsgTools/AsgMetadataTool.h +++ b/Control/AthToolSupport/AsgTools/AsgTools/AsgMetadataTool.h @@ -1,5 +1,5 @@ // Dear emacs, this is -*- c++ -*- -// $Id: AsgMetadataTool.h 676319 2015-06-18 12:12:45Z krasznaa $ +// $Id: AsgMetadataTool.h 771072 2016-08-31 14:50:22Z krasznaa $ #ifndef ASGTOOLS_ASGMETADATATOOL_H #define ASGTOOLS_ASGMETADATATOOL_H @@ -41,8 +41,8 @@ namespace asg { /// /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> /// - /// $Revision: 676319 $ - /// $Date: 2015-06-18 14:12:45 +0200 (Thu, 18 Jun 2015) $ + /// $Revision: 771072 $ + /// $Date: 2016-08-31 16:50:22 +0200 (Wed, 31 Aug 2016) $ /// class AsgMetadataTool : public AsgTool, public virtual IIncidentListener { @@ -127,6 +127,10 @@ namespace asg { /// Object accessing the output metadata store mutable MetaStore_t m_outputMetaStore; + /// Flag helping to discover when the tool misses the opening of the first + /// input file + bool m_beginInputFileCalled; + }; // class AsgMetadataTool } // namespace asg diff --git a/Control/AthToolSupport/AsgTools/AsgTools/AsgTool.h b/Control/AthToolSupport/AsgTools/AsgTools/AsgTool.h index db463ee70ab99a53882200c725701f87fae1c1e7..d539ed1d0916c267f0d49bca163a62bcdd8548cf 100644 --- a/Control/AthToolSupport/AsgTools/AsgTools/AsgTool.h +++ b/Control/AthToolSupport/AsgTools/AsgTools/AsgTool.h @@ -1,5 +1,5 @@ // Dear emacs, this is -*- c++ -*- -// $Id: AsgTool.h 741760 2016-04-20 20:12:12Z ssnyder $ +// $Id: AsgTool.h 790658 2016-12-20 20:54:19Z leggett $ #ifndef ASGTOOLS_ASGTOOL_H #define ASGTOOLS_ASGTOOL_H @@ -12,15 +12,15 @@ #ifdef ASGTOOL_STANDALONE # include "AsgTools/AsgMessaging.h" # include "AsgTools/SgTEvent.h" + // Forward declaration(s): + class Property; + class PropertyMgr; #elif defined(ASGTOOL_ATHENA) # include "AthenaBaseComps/AthAlgTool.h" #else # error "What environment are we in?!?" #endif // Environment selection -// Forward declaration(s): -class Property; -class PropertyMgr; namespace asg { @@ -40,8 +40,8 @@ namespace asg { /// /// @author David Adams <dladams@bnl.gov> /// - /// $Revision: 741760 $ - /// $Date: 2016-04-20 22:12:12 +0200 (Wed, 20 Apr 2016) $ + /// $Revision: 790658 $ + /// $Date: 2016-12-20 21:54:19 +0100 (Tue, 20 Dec 2016) $ /// class AsgTool : public virtual IAsgTool, public AsgToolBase { diff --git a/Control/AthToolSupport/AsgTools/AsgTools/MessageCheck.h b/Control/AthToolSupport/AsgTools/AsgTools/MessageCheck.h index 0c460c37ac091eec24533d3b04b986c6eecfa613..b309533d3d65742bedc82724daedd92bf3c3eaf2 100644 --- a/Control/AthToolSupport/AsgTools/AsgTools/MessageCheck.h +++ b/Control/AthToolSupport/AsgTools/AsgTools/MessageCheck.h @@ -78,9 +78,9 @@ #include <type_traits> +#include <xAODRootAccess/tools/TReturnCode.h> #ifdef ROOTCORE #include <AsgTools/MsgStream.h> -#include <xAODRootAccess/tools/TReturnCode.h> #else #include "AthenaBaseComps/AthMessaging.h" #endif @@ -199,7 +199,6 @@ namespace asg return StatusCode::FAILURE;} }; -#ifdef ROOTCORE template<> struct CheckHelper<xAOD::TReturnCode> { /// \brief whether the status code reports a success @@ -214,7 +213,6 @@ namespace asg static inline decltype (xAOD::TReturnCode::kFailure) failureCode () { return xAOD::TReturnCode::kFailure;} }; -#endif template<> struct CheckHelper<int> { diff --git a/Control/AthToolSupport/AsgTools/AsgTools/ToolHandle.h b/Control/AthToolSupport/AsgTools/AsgTools/ToolHandle.h index c6d3bb5995ff48f0d701db7bb41a3d925a6257fe..2d13f3bf25bca8cf2a9b4eb4500dd50f1d1be020 100644 --- a/Control/AthToolSupport/AsgTools/AsgTools/ToolHandle.h +++ b/Control/AthToolSupport/AsgTools/AsgTools/ToolHandle.h @@ -1,5 +1,5 @@ // Dear emacs, this is -*- c++ -*- -// $Id: ToolHandle.h 724296 2016-02-16 16:24:42Z will $ +// $Id: ToolHandle.h 784417 2016-11-15 19:50:05Z krumnack $ #ifndef ASGTOOLS_TOOLHANDLE_H #define ASGTOOLS_TOOLHANDLE_H @@ -29,8 +29,8 @@ namespace asg { /// /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> /// -/// $Revision: 724296 $ -/// $Date: 2016-02-16 17:24:42 +0100 (Tue, 16 Feb 2016) $ +/// $Revision: 784417 $ +/// $Date: 2016-11-15 20:50:05 +0100 (Tue, 15 Nov 2016) $ /// class ToolHandleBase { @@ -72,8 +72,8 @@ protected: /// @author David Adams <dladams@bnl.gov> /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> /// -/// $Revision: 724296 $ -/// $Date: 2016-02-16 17:24:42 +0100 (Tue, 16 Feb 2016) $ +/// $Revision: 784417 $ +/// $Date: 2016-11-15 20:50:05 +0100 (Tue, 15 Nov 2016) $ /// template< class T > class ToolHandle : public ToolHandleBase { @@ -89,9 +89,13 @@ public: ToolHandle( const std::string& toolname, asg::IAsgTool* parent = 0 ); /// Dereferencing operator - T& operator*() const; + T& operator*(); /// Dereferencing operator - T* operator->() const; + const T& operator*() const; + /// Dereferencing operator + T* operator->(); + /// Dereferencing operator + const T* operator->() const; /// Retrieve tool. /// For compatibility with Gaudi. diff --git a/Control/AthToolSupport/AsgTools/AsgTools/ToolHandle.icc b/Control/AthToolSupport/AsgTools/AsgTools/ToolHandle.icc index 378b6b8cabd8cc38d21f3027fd2a9d7ef7ef4661..01a90030113d7f09585c058e3e8e56a752771df5 100644 --- a/Control/AthToolSupport/AsgTools/AsgTools/ToolHandle.icc +++ b/Control/AthToolSupport/AsgTools/AsgTools/ToolHandle.icc @@ -1,5 +1,5 @@ // Dear emacs, this is -*- c++ -*- -// $Id: ToolHandle.icc 724348 2016-02-16 20:16:11Z krumnack $ +// $Id: ToolHandle.icc 784417 2016-11-15 19:50:05Z krumnack $ #ifndef ASGTOOLS_TOOLHANDLE_ICC #define ASGTOOLS_TOOLHANDLE_ICC @@ -26,7 +26,7 @@ ToolHandle< T >::ToolHandle( const std::string& typeAndName, asg::IAsgTool* pare } template< class T > -T& ToolHandle< T >::operator*() const { +T& ToolHandle< T >::operator*() { // Retrieve the tool pointer if necessary: if( ! m_ptool ) { @@ -43,7 +43,41 @@ T& ToolHandle< T >::operator*() const { } template< class T > -T* ToolHandle<T>::operator->() const { +const T& ToolHandle< T >::operator*() const { + + // Retrieve the tool pointer if necessary: + if( ! m_ptool ) { + m_ptool = asg::ToolStore::get< T >( name() ); + } + // Check if we succeeded: + if( ! m_ptool ) { + throw std::runtime_error( "Couldn't find tool with name \"" + + name() + "\"" ); + } + + // Return a reference to the tool: + return *m_ptool; +} + +template< class T > +T* ToolHandle<T>::operator->() { + + // Retrieve the tool pointer if necessary: + if( ! m_ptool ) { + m_ptool = asg::ToolStore::get< T >( name() ); + } + // Check if we succeeded: + if( ! m_ptool ) { + throw std::runtime_error( "Couldn't find tool with name \"" + + name() + "\"" ); + } + + // Return the (possibly null-)pointer to the tool: + return m_ptool; +} + +template< class T > +const T* ToolHandle<T>::operator->() const { // Retrieve the tool pointer if necessary: if( ! m_ptool ) { @@ -95,7 +129,7 @@ std::ostream& operator<<( std::ostream& out, const ToolHandle< T >& handle ) { out << "ASG ToolHandle with name = \"" << handle.name() << "\", pointer = "; - T* ptool = nullptr; + const T* ptool = nullptr; if (handle.retrieve()) ptool = handle.operator->(); out << ptool; diff --git a/Control/AthToolSupport/AsgTools/CMakeLists.txt b/Control/AthToolSupport/AsgTools/CMakeLists.txt index 93faca157a9d7106c44551fbd41a167d3bc16194..73e7f42a3b48a04d111dd83ba7847f9e99a82fe5 100644 --- a/Control/AthToolSupport/AsgTools/CMakeLists.txt +++ b/Control/AthToolSupport/AsgTools/CMakeLists.txt @@ -1,4 +1,4 @@ -# $Id: CMakeLists.txt 745006 2016-05-05 10:40:32Z will $ +# $Id: CMakeLists.txt 790389 2016-12-18 13:39:12Z krumnack $ ################################################################################ # Package: AsgTools ################################################################################ @@ -12,7 +12,7 @@ if( XAOD_STANDALONE ) set( deps Control/xAODRootAccessInterfaces Control/xAODRootAccess ) set( libs xAODRootAccessInterfaces xAODRootAccess ) else() - set( deps Control/AthenaBaseComps Control/SGTools Database/IOVDbDataModel + set( deps Control/xAODRootAccess Control/AthenaBaseComps Control/SGTools Database/IOVDbDataModel GaudiKernel ) set( libs AthenaBaseComps SGTools IOVDbDataModel GaudiKernel ) endif() @@ -47,6 +47,12 @@ atlas_add_dictionary( AsgToolsDict AsgTools/AsgToolsDict.h AsgTools/selection.xml LINK_LIBRARIES AsgTools ) +# Silence some warnings that are generated by the code on MacOS X: +set( extra_defs ) +if( APPLE AND TARGET AsgTools ) + target_compile_options( AsgTools PUBLIC -Wno-tautological-undefined-compare ) +endif() + # Test(s) in the package: atlas_add_test( gt_UnitTest_test SOURCES test/gt_UnitTest_test.cxx diff --git a/Control/AthToolSupport/AsgTools/Root/AnaToolHandle.cxx b/Control/AthToolSupport/AsgTools/Root/AnaToolHandle.cxx index 1020e48ff8fede41bd53c60830d1e1edaee3e465..8eb992aa14ad381b2090765e84da60711d5a3ea9 100644 --- a/Control/AthToolSupport/AsgTools/Root/AnaToolHandle.cxx +++ b/Control/AthToolSupport/AsgTools/Root/AnaToolHandle.cxx @@ -30,6 +30,99 @@ // method implementations // +namespace asg +{ + namespace detail + { + AnaToolShare :: + AnaToolShare (const ToolHandle<interfaceType_t>& val_th, + AnaToolCleanup val_cleanup) + : m_th (val_th), m_cleanup (std::move (val_cleanup)) + { + assert (!m_th.empty()); + } + + + + ToolHandle<interfaceType_t>& AnaToolShare :: + th () + { + assert (!m_th.empty()); + return m_th; + } + + + + AnaToolShareList& AnaToolShareList :: + singleton () noexcept + { + static AnaToolShareList result; + return result; + } + + + + std::shared_ptr<AnaToolShare> AnaToolShareList :: + getShare (const std::string& name) const + { + auto iter = m_shared.find (name); + if (iter == m_shared.end()) + return std::shared_ptr<AnaToolShare> (); + return iter->second.lock(); + } + + + + std::shared_ptr<AnaToolShare> AnaToolShareList :: + setShare (const std::string& name, + std::unique_ptr<AnaToolShare> val_share) + { + std::shared_ptr<AnaToolShare> result = getShare (name); + if (result != nullptr) + return result; + result.reset (val_share.release ()); + m_shared[name] = result; + return result; + } + + + + StatusCode AnaToolShareList :: + makeShare (const std::string& name, + const AnaToolConfig& config, + std::shared_ptr<AnaToolShare>& result) + { + using namespace msgToolHandle; + + auto& share = m_shared[name]; + auto res_result = share.lock(); + if (res_result != nullptr) + { + result = res_result; + return StatusCode::SUCCESS; + } + ToolHandle<interfaceType_t> th; + AnaToolCleanup cleanup; + ANA_CHECK (config.makeTool (name, nullptr, th, cleanup)); + res_result.reset (new AnaToolShare (th, cleanup)); +#ifndef ROOTCORE + if (!th.empty()) + { + th->release (); + } +#endif + assert (share.lock() == nullptr); + share = res_result; + result = res_result; + return StatusCode::SUCCESS; + } + } +} + +// +// legacy code +// + #ifdef ROOTCORE namespace asg @@ -147,7 +240,7 @@ namespace asg auto tools = toolSvc->getTools(); bool out(false); for(auto atool : tools) { - if(atool->name() == fullName) {out=true;tool=atool;break;} + if(atool && atool->name() == fullName) {out=true;tool=atool;break;} } toolSvc.release().ignore(); return out; @@ -189,11 +282,328 @@ namespace asg if(joSvc.release().isFailure()) return StatusCode::FAILURE; return StatusCode::SUCCESS; } + } +} +#endif +namespace asg +{ + namespace detail + { + void AnaToolConfig :: + swap (AnaToolConfig& that) noexcept + { + m_type.swap (that.m_type); + m_factory.swap (that.m_factory); + m_properties.swap (that.m_properties); + } + + + + bool AnaToolConfig :: + empty () const noexcept + { + if (!m_properties.empty()) + return false; + if (!m_type.empty()) + return false; +#ifdef ROOTCORE + if (m_factory) + return false; +#endif + return true; + } + + + + const std::string& AnaToolConfig :: + type () const noexcept + { + return m_type; + } + + + + void AnaToolConfig :: + setType (std::string type) noexcept + { + m_type = std::move (type); + } + + + void AnaToolConfig :: + addProperty (const std::string& name, + const std::shared_ptr<AnaToolProperty>& property) + { + m_properties[name] = property; + } + + + +#ifdef ROOTCORE + StatusCode AnaToolConfig :: + allocateTool (AsgTool*& toolPtr, const std::string& toolName) const + { + using namespace msgToolHandle; + + if (m_factory) + { + ANA_CHECK (m_factory (toolPtr, toolName)); + return StatusCode::SUCCESS; + } + + try + { + ANA_CHECK (detail::makeToolRootCore (type(), toolName, toolPtr)); + } catch (std::exception& e) + { + ANA_MSG_ERROR ("encountered exception during tool creation(" << + type() << "," << toolName << "): " << e.what()); + return StatusCode::FAILURE; + } + if (toolPtr == nullptr) + { + ANA_MSG_ERROR ("failed to allocate tool, this is typically caused either by the tool inheriting from AsgTool virtually or because its first base class is not AsgTool): " + type()); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; } +#endif -} +#ifndef ROOTCORE + StatusCode AnaToolConfig :: + applyPropertiesAthena (const std::string& toolName, + AnaToolCleanup& cleanup) const + { + using namespace msgToolHandle; + + for (auto& property : m_properties) + { + ANA_CHECK (property.second->applyPropertyAthena + (toolName, property.first, cleanup)); + } + return StatusCode::SUCCESS; + } +#endif + + + + /* + namespace + { + /// convert the cleanup list into a single cleanup pointer + std::shared_ptr<void> + compressCleanup (std::list<std::shared_ptr<void> >& baseCleanup) + { + if (baseCleanup.empty()) + return std::shared_ptr<void> (); + if (baseCleanup.size() == 1) + return baseCleanup.front(); + return std::shared_ptr<std::vector<std::shared_ptr<void> > > + (new std::vector<std::shared_ptr<void> > (baseCleanup.begin(), + baseCleanup.end())); + } + } + */ + + + +#ifdef ROOTCORE + StatusCode AnaToolConfig :: + makeToolRootCore (const std::string& toolName, IAsgTool*& toolPtr, + AnaToolCleanup& cleanup) const + { + using namespace msgToolHandle; + + asg::AsgTool *rawToolPtr = nullptr; + ANA_CHECK (allocateTool (rawToolPtr, toolName)); + std::shared_ptr<AsgTool> sharedPtr (rawToolPtr); + AnaToolCleanup mycleanup; + + for (auto& property : m_properties) + { + ANA_CHECK (property.second->applyPropertyRootCore + (*rawToolPtr, property.first, mycleanup)); + } + ANA_CHECK (rawToolPtr->initialize()); + + mycleanup.addCleanup (sharedPtr, false); + cleanup.swap (mycleanup); + toolPtr = sharedPtr.get(); + return StatusCode::SUCCESS; + } +#endif + + +#ifndef ROOTCORE + /// \brief manage the reference count on a tool + + struct ToolRefManager + { + ToolRefManager (const ToolHandle<IAlgTool>& val_tool, bool addRef) + : m_tool (val_tool), m_releases (m_tool->refCount()) + { + if (addRef) + { + m_tool->addRef(); + ++ m_releases; + } + } + + ~ToolRefManager () + { + using namespace msgToolHandle; + assert (m_releases <= m_tool->refCount()); + if (m_releases > 0) + { + // for (unsigned iter = 1, end = m_tool->refCount(); iter != end; ++ iter) + for (unsigned iter = 1; iter != m_releases; ++ iter) + m_tool->release(); + ANA_CHECK_THROW (m_tool.release()); + } + } + + ToolHandle<IAlgTool> m_tool; + unsigned m_releases = 0; + }; + + + + StatusCode AnaToolPropertyValueAthena :: + applyPropertyAthena (const std::string& toolName, + const std::string& name, + AnaToolCleanup& /*cleanup*/) + const + { + using namespace msgToolHandle; + + // this is so we clear out properties from catalogue when tool + // is destroyed. DISABLED: we no longer clear out tools in Athena + // std::shared_ptr<PropertyValueManager> manager + // (new PropertyValueManager (toolName, name)); + // cleanup.addCleanup (manager); + + // for athena we hand our property to the joboptions svc + ANA_CHECK (detail::addPropertyToCatalogue (toolName, name, m_value)); + // manager->m_cleanup = true; + return StatusCode::SUCCESS; + } #endif + + + + StatusCode AnaToolConfig :: + makeBaseTool (const std::string& name, + parentType_t *parent, + ToolHandle<interfaceType_t>& th, + AnaToolCleanup& cleanup) const + { + using namespace msgToolHandle; + + std::string toolName; + if (parent) + toolName = parent->name() + "." + name; + else + toolName = "ToolSvc." + name; + +#ifdef ROOTCORE + interfaceType_t *baseToolPtr = nullptr; + AnaToolCleanup baseCleanup; + ANA_CHECK (makeToolRootCore (toolName, baseToolPtr, baseCleanup)); + th = ToolHandle<interfaceType_t> (baseToolPtr); + cleanup.swap (baseCleanup); +#else + AnaToolCleanup baseCleanup; + ANA_CHECK (applyPropertiesAthena (toolName, baseCleanup)); + ToolHandle<interfaceType_t> myth (m_type + "/" + name, parent); + ANA_CHECK (myth.retrieve()); + // disabling this as it causes crashes in offline. if you + // re-enable this, also reenable the cleanup tools in + // applyPropertiesAthena + // std::shared_ptr<detail::ToolRefManager> manager + // (new detail::ToolRefManager (myth, true)); + // baseCleanup.addCleanup (manager, false); + th = myth; + myth->release (); + cleanup.swap (baseCleanup); +#endif + return StatusCode::SUCCESS; + } + + + + void AnaToolCleanup :: + swap (AnaToolCleanup& that) + { + m_cleanup.swap (that.m_cleanup); + } + + + + void AnaToolCleanup :: + addCleanup (AnaToolCleanup val_cleanup, bool post) + { + if (post) + { + for (auto& cleanup : val_cleanup.m_cleanup) + m_cleanup.push_back (cleanup); + } else + { + val_cleanup.addCleanup (*this, true); + m_cleanup.swap (val_cleanup.m_cleanup); + } + } + + + + void AnaToolCleanup :: + addCleanup (const std::shared_ptr<void>& val_cleanup, + bool post) + { + if (val_cleanup) + { + if (post) + m_cleanup.push_back (val_cleanup); + else + m_cleanup.push_front (val_cleanup); + } + } + + + + StatusCode AnaToolConfig :: + setProperty (const std::string& val_name, const char *val_value) + { + return setProperty (val_name, std::string (val_value)); + } + + + +#ifndef ROOTCORE + AnaToolPropertyCopyTool :: + AnaToolPropertyCopyTool (const std::string& val_type, + const std::string& val_name) + : m_type (val_type), m_name (val_name) + { + } + + StatusCode AnaToolPropertyCopyTool :: + applyPropertyAthena (const std::string& toolName, + const std::string& name, + AnaToolCleanup& /*cleanup*/) + const + { + using namespace msgToolHandle; + + std::string myname = toolName + "." + name; + + ANA_CHECK (addPropertyToCatalogue (toolName, name, m_type + "/" + name)); + ANA_CHECK (copyPropertiesInCatalogue (m_name, myname)); + return StatusCode::SUCCESS; + } +#endif + } +} diff --git a/Control/AthToolSupport/AsgTools/Root/AsgMessaging.cxx b/Control/AthToolSupport/AsgTools/Root/AsgMessaging.cxx index 6e84fdd8d909c52777337a5e6171c9b373d027d2..2ca7c479e09b9f4c482014bf7adf99dcafb1ad5c 100644 --- a/Control/AthToolSupport/AsgTools/Root/AsgMessaging.cxx +++ b/Control/AthToolSupport/AsgTools/Root/AsgMessaging.cxx @@ -1,4 +1,4 @@ -// $Id: AsgMessaging.cxx 615798 2014-09-09 16:02:17Z krasznaa $ +// $Id: AsgMessaging.cxx 784571 2016-11-16 14:27:23Z will $ // Local include(s): #include "AsgTools/AsgMessaging.h" @@ -15,7 +15,7 @@ namespace asg { AsgMessaging::AsgMessaging( const std::string& name ) : #ifdef ASGTOOL_ATHENA - AthMessaging( Gaudi::svcLocator()->service< IMessageSvc >( "MessageSvc" ), + AthMessaging( Gaudi::svcLocator()->service< IMessageSvc >( "MessageSvc", false ), name ) #elif defined(ASGTOOL_STANDALONE) m_msg( name ) @@ -29,7 +29,7 @@ namespace asg { AsgMessaging::AsgMessaging( const IAsgTool* tool ) : #ifdef ASGTOOL_ATHENA - AthMessaging( Gaudi::svcLocator()->service< IMessageSvc >( "MessageSvc" ), + AthMessaging( Gaudi::svcLocator()->service< IMessageSvc >( "MessageSvc", false ), tool->name() ) #elif defined(ASGTOOL_STANDALONE) m_msg( tool ) diff --git a/Control/AthToolSupport/AsgTools/Root/AsgMetadataTool.cxx b/Control/AthToolSupport/AsgTools/Root/AsgMetadataTool.cxx index b7b3392bdf009494c7a52b9ec2d505fac9dc0ed9..6b6c3e0ba21476c0c121ab3bde793f33ce9ba6ac 100644 --- a/Control/AthToolSupport/AsgTools/Root/AsgMetadataTool.cxx +++ b/Control/AthToolSupport/AsgTools/Root/AsgMetadataTool.cxx @@ -1,4 +1,4 @@ -// $Id: AsgMetadataTool.cxx 692722 2015-09-02 13:06:02Z krasznaa $ +// $Id: AsgMetadataTool.cxx 771072 2016-08-31 14:50:22Z krasznaa $ // System include(s): #include <stdexcept> @@ -36,11 +36,12 @@ namespace asg { : AsgTool( name ), #ifdef ASGTOOL_STANDALONE m_inputMetaStore( SgTEventMeta::InputStore ), - m_outputMetaStore( SgTEventMeta::OutputStore ) + m_outputMetaStore( SgTEventMeta::OutputStore ), #elif defined(ASGTOOL_ATHENA) m_inputMetaStore( "StoreGateSvc/InputMetaDataStore", name ), - m_outputMetaStore( "StoreGateSvc/MetaDataStore", name ) + m_outputMetaStore( "StoreGateSvc/MetaDataStore", name ), #endif // Environment selection + m_beginInputFileCalled( false ) { #ifdef ASGTOOL_STANDALONE @@ -132,6 +133,7 @@ namespace asg { // Call the appropriate member function: if( inc.type() == IncidentType::BeginInputFile ) { + m_beginInputFileCalled = true; if( beginInputFile().isFailure() ) { ATH_MSG_FATAL( "Failed to call beginInputFile()" ); throw std::runtime_error( "Couldn't call beginInputFile()" ); @@ -142,6 +144,16 @@ namespace asg { throw std::runtime_error( "Couldn't call endInputFile()" ); } } else if( inc.type() == IncidentType::BeginEvent ) { + // If the tool didn't catch the begin input file incident for the + // first input file of the job, then call the appropriate function + // now. + if( ! m_beginInputFileCalled ) { + m_beginInputFileCalled = true; + if( beginInputFile().isFailure() ) { + ATH_MSG_FATAL( "Failed to call beginInputFile()" ); + throw std::runtime_error( "Couldn't call beginInputFile()" ); + } + } if( beginEvent().isFailure() ) { ATH_MSG_FATAL( "Failed to call beginEvent()" ); throw std::runtime_error( "Couldn't call beginEvent()" ); diff --git a/Control/AthToolSupport/AsgTools/cmt/requirements b/Control/AthToolSupport/AsgTools/cmt/requirements index 8c5de4a13e2e94c01efa959156864ddd03554b6a..f1f249dd5a01f2c2df90a6e2c746ddc259596ff3 100644 --- a/Control/AthToolSupport/AsgTools/cmt/requirements +++ b/Control/AthToolSupport/AsgTools/cmt/requirements @@ -1,5 +1,5 @@ package AsgTools -# $Id: requirements 745006 2016-05-05 10:40:32Z will $ +# $Id: requirements 790389 2016-12-18 13:39:12Z krumnack $ author David Adams @@ -7,6 +7,8 @@ public use AtlasPolicy AtlasPolicy-* +use xAODRootAccess xAODRootAccess-* Control + use GaudiInterface GaudiInterface-* External #use AtlasGoogleTest AtlasGoogleTest-* External