From 2a0ab82dd67e85e3f2154aec09a50067264e8217 Mon Sep 17 00:00:00 2001 From: Scott Snyder <scott.snyder@cern.ch> Date: Tue, 27 Dec 2016 22:47:02 +0100 Subject: [PATCH] 'Use STL version of unordered_map.' (AthenaKernel-00-60-09) * Tagging AthenaKernel-00-60-09. * Use STL version of unordered_map. 2016-12-08 Peter van Gemmeren <gemmeren@anl.gov> * Tagging AthenaKernel-00-60-08 * AthenaKernel/IAthenaSelectorTool.h: Make preNext() and postNext() const to deal with Gaudi changes. 2016-12-07 Jack Cranshaw <cranshaw@anl.gov> * Change IDecisionSvc get methods to return reference rather than pointer * extend isEventAccepted to be EventContext aware * AthenaKernel-00-60-07 2016-12-02 Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> * Removed the genCLIDDB executable from the package, to move it to CLIDComps instead. * Updated the package's CMake configuration to be a bit more ... (Long ChangeLog diff - truncated) --- Control/AthenaKernel/AthenaKernel/DsoDb.h | 4 +- .../AthenaKernel/IAthenaSelectorTool.h | 4 +- .../AthenaKernel/IAthenaSerializeSvc.h | 7 +- .../AthenaKernel/AthenaKernel/IDecisionSvc.h | 10 +- .../AthenaKernel/IEvtIdModifierSvc.h | 2 +- .../AthenaKernel/AthenaKernel/IInputRename.h | 61 +++ Control/AthenaKernel/AthenaKernel/IRCUSvc.h | 87 ++++ Control/AthenaKernel/AthenaKernel/RCUObject.h | 484 ++++++++++++++++++ .../AthenaKernel/AthenaKernel/RCUObject.icc | 365 +++++++++++++ .../AthenaKernel/AthenaKernel/StreamLogger.h | 73 --- .../AthenaKernel/AthenaKernel/errorcheck.h | 4 +- Control/AthenaKernel/CMakeLists.txt | 120 +++-- Control/AthenaKernel/cmt/requirements | 6 +- Control/AthenaKernel/share/IRCUSvc_test.ref | 1 + Control/AthenaKernel/share/RCUObject_test.ref | 3 + Control/AthenaKernel/src/IClassIDSvc.cxx | 49 -- Control/AthenaKernel/src/RCUObject.cxx | 60 +++ Control/AthenaKernel/src/StreamLogger.cxx | 68 --- Control/AthenaKernel/test/IRCUSvc_test.cxx | 73 +++ Control/AthenaKernel/test/RCUObject_test.cxx | 265 ++++++++++ Control/AthenaKernel/test/errorcheck_test.cxx | 6 +- Control/AthenaKernel/utils/genCLIDDB.cxx | 138 ----- 22 files changed, 1479 insertions(+), 411 deletions(-) create mode 100644 Control/AthenaKernel/AthenaKernel/IInputRename.h create mode 100644 Control/AthenaKernel/AthenaKernel/IRCUSvc.h create mode 100644 Control/AthenaKernel/AthenaKernel/RCUObject.h create mode 100644 Control/AthenaKernel/AthenaKernel/RCUObject.icc delete mode 100644 Control/AthenaKernel/AthenaKernel/StreamLogger.h create mode 100644 Control/AthenaKernel/share/IRCUSvc_test.ref create mode 100644 Control/AthenaKernel/share/RCUObject_test.ref delete mode 100644 Control/AthenaKernel/src/IClassIDSvc.cxx create mode 100644 Control/AthenaKernel/src/RCUObject.cxx delete mode 100644 Control/AthenaKernel/src/StreamLogger.cxx create mode 100644 Control/AthenaKernel/test/IRCUSvc_test.cxx create mode 100644 Control/AthenaKernel/test/RCUObject_test.cxx delete mode 100644 Control/AthenaKernel/utils/genCLIDDB.cxx diff --git a/Control/AthenaKernel/AthenaKernel/DsoDb.h b/Control/AthenaKernel/AthenaKernel/DsoDb.h index 253773f42d0..734e92c319a 100644 --- a/Control/AthenaKernel/AthenaKernel/DsoDb.h +++ b/Control/AthenaKernel/AthenaKernel/DsoDb.h @@ -16,7 +16,7 @@ #include <string> #include <vector> #include <map> -#include "CxxUtils/unordered_map.h" // migrate to STL +#include <unordered_map> #include "DataModelRoot/RootType.h" @@ -33,7 +33,7 @@ class DsoDb /////////////////////////////////////////////////////////////////// public: typedef std::vector<std::string> Libs_t; - typedef SG::unordered_map<std::string, Libs_t> DsoMap_t; + typedef std::unordered_map<std::string, Libs_t> DsoMap_t; //typedef std::map<std::string, Libs_t> DsoMap_t; // helper functions for pythonizations diff --git a/Control/AthenaKernel/AthenaKernel/IAthenaSelectorTool.h b/Control/AthenaKernel/AthenaKernel/IAthenaSelectorTool.h index e6eda6ac25e..02bd377a273 100644 --- a/Control/AthenaKernel/AthenaKernel/IAthenaSelectorTool.h +++ b/Control/AthenaKernel/AthenaKernel/IAthenaSelectorTool.h @@ -28,9 +28,9 @@ public: /// Called at the end of initialize virtual StatusCode postInitialize() = 0; /// Called at the beginning of next - virtual StatusCode preNext() = 0; + virtual StatusCode preNext() const = 0; /// Called at the end of next - virtual StatusCode postNext() = 0; + virtual StatusCode postNext() const = 0; /// Called at the beginning of finalize virtual StatusCode preFinalize() = 0; /// Finalize AlgTool diff --git a/Control/AthenaKernel/AthenaKernel/IAthenaSerializeSvc.h b/Control/AthenaKernel/AthenaKernel/IAthenaSerializeSvc.h index e95cebc0075..21d43ab034c 100644 --- a/Control/AthenaKernel/AthenaKernel/IAthenaSerializeSvc.h +++ b/Control/AthenaKernel/AthenaKernel/IAthenaSerializeSvc.h @@ -6,6 +6,7 @@ #define ATHENAKERNEL_IATHENASERIALIZESVC_H #include "GaudiKernel/IService.h" +#include "DataModelRoot/RootType.h" class Guid; @@ -17,9 +18,11 @@ public: virtual void* serialize(const void* object, const std::string& name, size_t& nbytes) = 0; virtual void* serialize(const void* object, const Guid& id, size_t& nbytes) = 0; + virtual void* serialize(const void* object, const RootType& cltype, size_t& nbytes) = 0; - virtual void* deserialize(void* buffer, size_t nbytes, const std::string& name) = 0; - virtual void* deserialize(void* buffer, size_t nbytes, const Guid& id) = 0; + virtual void* deserialize(void* buffer, size_t& nbytes, const std::string& name) = 0; + virtual void* deserialize(void* buffer, size_t& nbytes, const Guid& id) = 0; + virtual void* deserialize(void* buffer, size_t& nbytes, const RootType& cltype) = 0; }; #endif diff --git a/Control/AthenaKernel/AthenaKernel/IDecisionSvc.h b/Control/AthenaKernel/AthenaKernel/IDecisionSvc.h index d1f8bdd0b0f..81a3a782838 100644 --- a/Control/AthenaKernel/AthenaKernel/IDecisionSvc.h +++ b/Control/AthenaKernel/AthenaKernel/IDecisionSvc.h @@ -25,6 +25,7 @@ // fwd declares class INamedInterface; +class EventContext; class IDecisionSvc @@ -57,19 +58,20 @@ public: // Get methods of Accept/Require/Veto algorithms for a given stream virtual - const std::vector<std::string> * getAcceptAlgs(const std::string& stream) const = 0; + const std::vector<std::string> getAcceptAlgs(const std::string& stream) const = 0; virtual - const std::vector<std::string> * getRequireAlgs(const std::string& stream) const = 0; + const std::vector<std::string> getRequireAlgs(const std::string& stream) const = 0; virtual - const std::vector<std::string> * getVetoAlgs(const std::string& stream) const = 0; + const std::vector<std::string> getVetoAlgs(const std::string& stream) const = 0; // Get list of streams - virtual const std::vector<std::string>* getStreams() const = 0; + virtual const std::vector<std::string> getStreams() const = 0; /// Test whether this event should be output, of a given stream virtual bool isEventAccepted(const std::string& stream) const = 0; + virtual bool isEventAccepted(const std::string& stream, const EventContext&) const = 0; static const InterfaceID& interfaceID(); diff --git a/Control/AthenaKernel/AthenaKernel/IEvtIdModifierSvc.h b/Control/AthenaKernel/AthenaKernel/IEvtIdModifierSvc.h index 1489ef446d1..397aae4afe4 100644 --- a/Control/AthenaKernel/AthenaKernel/IEvtIdModifierSvc.h +++ b/Control/AthenaKernel/AthenaKernel/IEvtIdModifierSvc.h @@ -55,7 +55,7 @@ class IEvtIdModifierSvc /** @brief return the current evt-nbr (after modification) */ - virtual number_type event_number() const =0; + virtual uint64_t event_number() const =0; /** @brief return the current time-stamp (after modification) */ diff --git a/Control/AthenaKernel/AthenaKernel/IInputRename.h b/Control/AthenaKernel/AthenaKernel/IInputRename.h new file mode 100644 index 00000000000..ec878efd39e --- /dev/null +++ b/Control/AthenaKernel/AthenaKernel/IInputRename.h @@ -0,0 +1,61 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/IInputRename.h + * @author scott snyder <snyder@bnl.gov> + * @date Sep, 2016 + * @brief Interface to retrieve input rename map. + */ + + +#ifndef ATHENAKERNEL_IINPUTRENAME_H +#define ATHENAKERNEL_IINPUTRENAME_H + + +#include "AthenaKernel/sgkey_t.h" +#include "AthenaKernel/RCUObject.h" +#include "GaudiKernel/IInterface.h" +#include <unordered_map> + + +namespace Athena { + + +/** + * @brief Interface to retrieve input rename map. + * + * The address remapping service may be configured to rename objects on input. + * When this is done, the keys stored in ElementLink/DataLink also need to + * be adjusted. This interface allows fetching a map that gives the + * needed transformation of SG keys. The returned object is + * synchronized via RCU. + */ +class IInputRename + : virtual public IInterface +{ +public: + /// Type of the input rename map: sgkey_t -> sgkey_t. + typedef std::unordered_map<SG::sgkey_t, SG::sgkey_t> InputRenameMap_t; + typedef RCUObject<InputRenameMap_t> InputRenameRCU_t; + + DeclareInterfaceID (IInputRename,1,0); + + + /** + * @brief Retrieve a pointer to the input rename map. + * + * May return null if no renaming is to be done. + */ + virtual const InputRenameRCU_t* inputRenameMap() const = 0; +}; + + +} // namespace Athena + + +#endif // not ATHENAKERNEL_IINPUTRENAME_H diff --git a/Control/AthenaKernel/AthenaKernel/IRCUSvc.h b/Control/AthenaKernel/AthenaKernel/IRCUSvc.h new file mode 100644 index 00000000000..96290c30f1c --- /dev/null +++ b/Control/AthenaKernel/AthenaKernel/IRCUSvc.h @@ -0,0 +1,87 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/IRCUSvc.h + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief read-copy-update (RCU) style synchronization for Athena. + */ + + +#ifndef ATHENAKERNEL_IRCUSVC_H +#define ATHENAKERNEL_IRCUSVC_H + + +#include "AthenaKernel/RCUObject.h" +#include "CxxUtils/make_unique.h" +#include "GaudiKernel/IInterface.h" +#include <memory> + + +namespace Athena { + + +/** + * @brief Interface for RCU service. + * + * See RCUObject.h for details of the RCU facility. + * + * The RCU service allows creating new RCU objects and registering + * them with the service, and also allows removing them from the service. + * The service will declare all registered RCU objects as quiescent + * at the end of an event. + */ +class IRCUSvc + : virtual public IInterface +{ +public: + DeclareInterfaceID (IRCUSvc,1,0); + + + /** + * @brief Make a new RCU object. + * @param args... Arguments to pass to the @c T constructor. + * + * The object will be registered with the service. + */ + template <class T, typename... Args> + std::unique_ptr<RCUObject<T> > newrcu (Args&&... args) + { + auto obj = CxxUtils::make_unique<RCUObject<T> > (*this, + std::forward<Args>(args)...); + add (obj.get()); + return obj; + } + + + /** + * @brief Remove an object from the service. + * @param obj The object to remove. + */ + virtual StatusCode remove (IRCUObject* obj) = 0; + + + /** + * @brief Return the number of event slots. + */ + virtual size_t getNumSlots() const = 0; + + +private: + /** + * @brief Remove an object from the service. + * @param obj The object to add. + */ + virtual void add (IRCUObject* obj) = 0; +}; + + +} // namespace Athena + + +#endif // not ATHENAKERNEL_IRCUSVC_H diff --git a/Control/AthenaKernel/AthenaKernel/RCUObject.h b/Control/AthenaKernel/AthenaKernel/RCUObject.h new file mode 100644 index 00000000000..44d75570d90 --- /dev/null +++ b/Control/AthenaKernel/AthenaKernel/RCUObject.h @@ -0,0 +1,484 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/RCUObject.h + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief read-copy-update (RCU) style synchronization for Athena. + * + * Read-copy-update (RCU) is a style of synchronization that is appropriate + * to a read-often, update-seldom case. More precisely: + * + * - Reads are frequent and low overhead is important. + * - Updates are infrequent, and extra overhead doesn't matter much. + * - Exact time ordering between reads and updates is not important. + * That is, if a read happens at about the same time as an update, + * it doesn't matter if the read sees the data before or after + * the update (as long as the reader sees something that is consistent). + * + * For a more detailed introduction see, for example: + * + * <https://lwn.net/Articles/262464> + * <https://lwn.net/Articles/573424> + * + * There are many different styles of RCU implemenation; the one we implement + * here is close to the `quiescent-state-based RCU' (QSBR) variant discussed + * in the second article above. Here, readers take out no locks whatsoever. + * It follows then that the updater cannot directly change the object + * that is being read. Instead, it makes an updated copy of the object + * and then publishes it by atomically changing a pointer to the object. + * The remaining question is then when can the old object be deleted. + * It is necessary to delay this until until no thread can be reading + * the old version of the object. + * + * In this implementation, the updater does not wait for this to happen. + * Instead, after the update, each event slot (other than the updater) + * is marked as being in a `grace' period (via an array of flags + * in RCUObject). A grace period ends for a given event slot when + * the object is declared `quiescent'; that is, it is at that time + * not referencing the object. Once the grace periods for all event + * slots have finished, then old versions of the object can be deleted. + * + * It is possible to explicitly declare an object as quiescent, either + * by calling the quiescent() method or by using RCUReadQuiesce. + * Objects can also be registered with the Athena RCUSvc, which will + * declare objects quiescent at the end of an event. + * + * The current implementation is very simple, and is suitable for a small + * number of objects that change infrequently. + * + * - If objects are being updated ~ every event and one is relying + * on RCUSvc to mark them as quiescent, then it's possible that we'll + * never be out of the grace period for all event slots simultaneously, + * preventing objects from being cleaned up. + * + * - If there are a large number of infrequently-changing objects, + * then RCUSvc may waste time marking as quiescent objects that + * have not changed. + * + * If either of these becomes an issue, they can be addressed with a more + * elaborate implementation. + * + * Usage: + * + * The usual usage is to create an RCUObject instance via the RCUSvc. + * RCUObject is templated on the type of the controlled object. + * + *@code + * ServiceHandle<Athena::RCUSvc> rcusvc ("Athean::RCUSvc", "test"); + * std::unique_ptr<Athena::RCUObject<Payload> > = + * rcusvc->newrcu<Payload>(); + @endcode + * + * @c newrcu may also take additional arguments that will be passed + * to the constructor for @c Payload. This will register the object + * with the service. One can alternately create a @c RCUObject directly, + * passing it the number of event slots. + * + * To read the controlled object, create a @c RCURead object: + * + *@code + * const Athena::RCUObject<Payload>& rcuobj = ...; + * { + * Athena::RCURead<Payload> r (rcuobj); + * ret = r->someMethodOnPayload(); + * } + @endcode + * + * and to update use @c RCUUpdate: + * + *@code + * Athena::RCUObject<Payload>& rcuobj = ...; + * { + * Athena::RCUUpdate<Payload> u (rcuobj); + * auto newPayload = std::make_unique<Payload> (*u); + * newPayload->updateSomeStuff(); + * u.update (std::move (newPayload)); + * } + @endcode + * + * To explicitly declare an object as quiescent, call the @c quiescent method. + * This takes an @c EventContext object, or it can be defaulted, in which + * case the current global context object will be used. You can also + * use @c RCUReadQuiesce instead of @c RCURead to automatically call + * @c quiescent when the read is complete (when the @c RCUReadQuiesce + * object is destroyed). + */ + + +#ifndef ATHENAKERNEL_RCUOBJECT_H +#define ATHENAKERNEL_RCUOBJECT_H + + +#include "CxxUtils/make_unique.h" +#include "GaudiKernel/ThreadLocalContext.h" +#include "GaudiKernel/EventContext.h" +#include "boost/dynamic_bitset.hpp" +#include <atomic> +#include <deque> +#include <vector> +#include <memory> +#include <mutex> + + +namespace Athena { + + +class IRCUSvc; +template <class T> class RCURead; +template <class T> class RCUReadQuiesce; +template <class T> class RCUUpdate; + + + +/** + * @brief Base object class for RCU-style synchronization for Athena. + */ +class IRCUObject +{ +public: + /** + * @brief Constructor, with RCUSvc. + * @param svc Service with which to register. + * + * The service will call @c quiescent at the end of each event. + */ + IRCUObject (IRCUSvc& svc); + + + /** + * @brief Constructor, with event slot count. + * @param nslots Number of active event slots. + * + * This version does not register with a service. + */ + IRCUObject (size_t nslots); + + + /** + * @brief Destructor. + * + * Remove this object from the service if it has been registered. + */ + virtual ~IRCUObject(); + + + /** + * @brief Declare the current event slot of this object to be quiescent. + * + * This will take out a lock and possibly trigger object cleanup. + */ + void quiescent(); + + + /** + * @brief Declare the event slot @c ctx of this object to be quiescent. + * @param ctx The event context. + * + * This will take out a lock and possibly trigger object cleanup. + */ + void quiescent (const EventContext& ctx); + + +protected: + typedef std::mutex mutex_t; + typedef std::lock_guard<mutex_t> lock_t; + + + /** + * @brief Declare that the grace period for a slot is ending. + * @param Lock object (external locking). + * @param ctx Event context for the slot. + * @returns true if any slot is still in a grace period. + * false if no slots are in a grace period. + * + * The caller must be holding the mutex for this object. + */ + bool endGrace (lock_t& /*lock*/, const EventContext& ctx); + + + /** + * @brief Declare that all slots are in a grace period. + * @param Lock object (external locking). + * @param ctx Event context for the slot. + * + * The caller must be holding the mutex for this object. + */ + void setGrace (lock_t& /*lock*/); + + + /** + * @brief Return the mutex for this object. + */ + mutex_t& mutex(); + + + /** + * @brief Delete all old objects. + * @param Lock object (external locking). + * + * The caller must be holding the mutex for this object. + */ + virtual void clearOld (lock_t& /*lock*/) = 0; + + +private: + /// The mutex for this object. + std::mutex m_mutex; + + /// The service with which we're registered, or null. + IRCUSvc* m_svc; + + /// Bit[i] set means that slot i is in a grace period. + boost::dynamic_bitset<> m_grace; +}; + + +/** + * @brief Wrapper object controlled by RCU synchonization. + * + * See the comments at the top of the file for complete comments. + */ +template <class T> +class RCUObject + : public IRCUObject +{ +public: + typedef RCURead<T> Read_t; + typedef RCUReadQuiesce<T> ReadQuiesce_t; + typedef RCUUpdate<T> Update_t; + + + /** + * @brief Constructor, with RCUSvc. + * @param svc Service with which to register. + * @param args... Additional arguments to pass to the @c T constructor. + * + * The service will call @c quiescent at the end of each event. + */ + template <typename... Args> + RCUObject (IRCUSvc& svc, Args&&... args); + + + /** + * @brief Constructor, with number of slots. + * @param nslots Number of event slots. + * @param args... Additional arguments to pass to the @c T constructor. + */ + template <typename... Args> + RCUObject (size_t nslots, Args&&... args); + + + /** + * @brief Return a reader for this @c RCUObject. + */ + Read_t reader() const; + + + /** + * @brief Return a reader for this @c RCUObject. + * When destroyed, this reader will declare + * the @c RCUObject as quiescent + * + * This version will read the global event context. + */ + ReadQuiesce_t readerQuiesce(); + + + /** + * @brief Return a reader for this @c RCUObject. + * When destroyed, this reader will declare + * the @c RCUObject as quiescent + * @param ctx The event context. + */ + ReadQuiesce_t readerQuiesce (const EventContext& ctx); + + + /** + * @brief Return an updater for this @c RCUObject. + * + * This version will read the global event context. + */ + Update_t updater(); + + + /** + * @brief Return an updater for this @c RCUObject. + * @param ctx The event context. + */ + Update_t updater (const EventContext& ctx); + + +private: + /** + * @brief Delete all old objects. + * @param Lock object (external locking). + * + * The caller must be holding the mutex for this object. + */ + virtual void clearOld (lock_t& /*lock*/) override; + + +private: + template <class U> friend class RCUReadQuiesce; + template <class U> friend class RCURead; + template <class U> friend class RCUUpdate; + + /// Pointer to the current object. + std::atomic<const T*> m_obj; + + /// List of all allocated objects. + /// The current object is the one at the front; + /// the others are pending cleanup. + std::deque<std::unique_ptr<T> > m_objs; +}; + + +/** + * @brief Helper to read data from a @c RCUObject. + * + * See the header comments for details. + */ +template <class T> +class RCURead +{ +public: + /** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + */ + RCURead (const RCUObject<T>& rcuobj); + + + /** + * @brief Access data. + */ + const T& operator*() const; + + + /** + * @brief Access data. + */ + const T* operator->() const; + + +private: + /// The data object we're reading. + const T& m_obj; +}; + + +/** + * @brief Helper to read data from a @c RCUObject. + * When this object is deleted, the @c RCUObject is declared + * quiescent for this event slot. + * + * See the header comments for details. + */ +template <class T> +class RCUReadQuiesce + : public RCURead<T> +{ +public: + /** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * + * This version will read the global event context. + */ + RCUReadQuiesce (RCUObject<T>& rcuobj); + + + /** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * @param ctx The event context. + */ + RCUReadQuiesce (RCUObject<T>& rcuobj, const EventContext& ctx); + + + /** + * @brief Destructor. + * + * Mark this event slot quiescent. + */ + ~RCUReadQuiesce(); + + +private: + /// The RCUObject we're referencing. + RCUObject<T>& m_rcuobj; + + /// The current event context. + const EventContext& m_ctx; +}; + + +/** + * @brief Helper to update data in a @c RCUObject. + * + * See the header comments for details. + */ +template <class T> +class RCUUpdate +{ +public: + /** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * + * This version will read the global event context. + */ + RCUUpdate (RCUObject<T>& rcuobj); + + + /** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * @param ctx The event context. + */ + RCUUpdate (RCUObject<T>& rcuobj, const EventContext& ctx); + + + /** + * @brief Access data. + */ + const T& operator*() const; + + + /** + * @brief Access data. + */ + const T* operator->() const; + + + /** + * @brief Publish a new version of the data object. + * @param ptr The new data object. + */ + void update (std::unique_ptr<T> ptr); + +private: + /// The object we're referencing. + RCUObject<T>& m_rcuobj; + + /// The event context. + const EventContext& m_ctx; + + /// Lock for synchonization. + std::lock_guard<std::mutex> m_g; +}; + + +} // namespace Athena + + +#include "AthenaKernel/RCUObject.icc" + + +#endif // not ATHENAKERNEL_RCUOBJECT_H diff --git a/Control/AthenaKernel/AthenaKernel/RCUObject.icc b/Control/AthenaKernel/AthenaKernel/RCUObject.icc new file mode 100644 index 00000000000..711487e5632 --- /dev/null +++ b/Control/AthenaKernel/AthenaKernel/RCUObject.icc @@ -0,0 +1,365 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/RCUObject.icc + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief read-copy-update (RCU) style synchronization for Athena. + */ + + +namespace Athena { + + +/** + * @brief Declare the current event slot of this object to be quiescent. + * + * This will take out a lock and possibly trigger object cleanup. + */ +inline +void IRCUObject::quiescent() +{ + quiescent (Gaudi::Hive::currentContext()); +} + + +/** + * @brief Declare the event slot @c ctx of this object to be quiescent. + * @param ctx The event context. + * + * This will take out a lock and possibly trigger object cleanup. + */ +inline +void IRCUObject::quiescent (const EventContext& ctx) +{ + std::lock_guard<std::mutex> g (m_mutex); + if (endGrace(g, ctx)) return; + clearOld(g); +} + + +/** + * @brief Declare that the grace period for a slot is ending. + * @param Lock object (external locking). + * @param ctx Event context for the slot. + * @returns true if any slot is still in a grace period. + * false if no slots are in a grace period. + * + * The caller must be holding the mutex for this object. + */ +inline +bool IRCUObject::endGrace (lock_t& /*lock*/, const EventContext& ctx) +{ + EventContext::ContextID_t slot = ctx.slot(); + if (slot == EventContext::INVALID_CONTEXT_ID) return false; + if (slot >= m_grace.size()) std::abort(); + m_grace[slot] = false; + return m_grace.any(); +} + + +/** + * @brief Declare that all slots are in a grace period. + * @param Lock object (external locking). + * @param ctx Event context for the slot. + * + * The caller must be holding the mutex for this object. + */ +inline +void IRCUObject::setGrace (lock_t& /*lock*/) +{ + m_grace.set(); +} + + +/** + * @brief Return the mutex for this object. + */ +inline +typename IRCUObject::mutex_t& IRCUObject::mutex() +{ + return m_mutex; +} + + +//************************************************************************* + + +/** + * @brief Constructor, with RCUSvc. + * @param svc Service with which to register. + * @param args... Additional arguments to pass to the @c T constructor. + * + * The service will call @c quiescent at the end of each event. + */ +template <class T> +template <typename... Args> +inline +RCUObject<T>::RCUObject (IRCUSvc& svc, Args&&... args) + : IRCUObject (svc) +{ + m_objs.push_back (CxxUtils::make_unique<T>(std::forward<Args>(args)...)); + m_obj = m_objs.front().get(); +} + + +/** + * @brief Constructor, with number of slots. + * @param nslots Number of event slots. + * @param args... Additional arguments to pass to the @c T constructor. + */ +template <class T> +template <typename... Args> +inline +RCUObject<T>::RCUObject (size_t nslots, Args&&... args) + : IRCUObject (nslots) +{ + m_objs.push_back (CxxUtils::make_unique<T>(std::forward<Args>(args)...)); + m_obj = m_objs.front().get(); +} + + +/** + * @brief Return a reader for this @c RCUObject. + */ +template <class T> +inline +typename RCUObject<T>::Read_t RCUObject<T>::reader() const +{ + return Read_t (*this); +} + + +/** + * @brief Return a reader for this @c RCUObject. + * When destroyed, this reader will declare + * the @c RCUObject as quiescent + * + * This version will read the global event context. + */ +template <class T> +inline +typename RCUObject<T>::ReadQuiesce_t RCUObject<T>::readerQuiesce() +{ + return ReadQuiesce_t (*this); +} + + +/** + * @brief Return a reader for this @c RCUObject. + * When destroyed, this reader will declare + * the @c RCUObject as quiescent + * @param ctx The event context. + */ +template <class T> +inline +typename RCUObject<T>::ReadQuiesce_t +RCUObject<T>::readerQuiesce (const EventContext& ctx) +{ + return ReadQuiesce_t (*this, ctx); +} + + +/** + * @brief Return an updater for this @c RCUObject. + * + * This version will read the global event context. + */ +template <class T> +inline +typename RCUObject<T>::Update_t RCUObject<T>::updater() +{ + return Update_t (*this); +} + + +/** + * @brief Return an updater for this @c RCUObject. + * + * This version will read the global event context. + */ +template <class T> +inline +typename RCUObject<T>::Update_t +RCUObject<T>::updater (const EventContext& ctx) +{ + return Update_t (*this, ctx); +} + + +/** + * @brief Delete all old objects. + * @param Lock object (external locking). + * + * The caller must be holding the mutex for this object. + */ +template <class T> +inline +void RCUObject<T>::clearOld (lock_t& /*lock*/) +{ + while (m_objs.size() > 1) + m_objs.pop_back(); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + */ +template <class T> +inline +RCURead<T>::RCURead (const RCUObject<T>& rcuobj) + : m_obj (*rcuobj.m_obj) +{ +} + + +/** + * @brief Access data. + */ +template <class T> +inline +const T& RCURead<T>::operator*() const +{ + return m_obj; +} + + +/** + * @brief Access data. + */ +template <class T> +inline +const T* RCURead<T>::operator->() const +{ + return &m_obj; +} + + +//************************************************************************* + + +/** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * + * This version will read the global event context. + */ +template <class T> +inline +RCUReadQuiesce<T>::RCUReadQuiesce (RCUObject<T>& rcuobj) + : RCURead<T> (rcuobj), + m_rcuobj (rcuobj), + m_ctx (Gaudi::Hive::currentContext()) +{ +} + + +/** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * @param ctx The event context. + */ +template <class T> +inline +RCUReadQuiesce<T>::RCUReadQuiesce (RCUObject<T>& rcuobj, + const EventContext& ctx) + : RCURead<T> (rcuobj), + m_rcuobj (rcuobj), + m_ctx (ctx) +{ +} + + +/** + * @brief Destructor. + * + * Mark this event slot quiescent. + */ +template <class T> +inline +RCUReadQuiesce<T>::~RCUReadQuiesce() +{ + m_rcuobj.quiescent (m_ctx); +} + + +//************************************************************************* + + +/** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * + * This version will read the global event context. + */ +template <class T> +inline +RCUUpdate<T>::RCUUpdate (RCUObject<T>& rcuobj) + : m_rcuobj (rcuobj), + m_ctx (Gaudi::Hive::currentContext()), + m_g (rcuobj.mutex()) +{ +} + + +/** + * @brief Constructor. + * @param rcuobj The @c RCUObject we're reading. + * @param ctx The event context. + */ +template <class T> +inline +RCUUpdate<T>::RCUUpdate (RCUObject<T>& rcuobj, const EventContext& ctx) + : m_rcuobj (rcuobj), + m_ctx (ctx), + m_g (rcuobj.mutex()) +{ +} + + +/** + * @brief Access data. + */ +template <class T> +inline +const T& RCUUpdate<T>::operator*() const +{ + return *m_rcuobj.m_obj; +} + + +/** + * @brief Access data. + */ +template <class T> +inline +const T* RCUUpdate<T>::operator->() const +{ + return m_rcuobj.m_obj; +} + + +/** + * @brief Publish a new version of the data object. + * @param ptr The new data object. + */ +template <class T> +void RCUUpdate<T>::update (std::unique_ptr<T> ptr) +{ + m_rcuobj.m_objs.push_front (std::move (ptr)); + m_rcuobj.m_obj = m_rcuobj.m_objs.front().get(); + m_rcuobj.setGrace(m_g); + + // Go ahead and end the grace period for the current slot. + m_rcuobj.endGrace(m_g, m_ctx); +} + + +} // namespace Athena diff --git a/Control/AthenaKernel/AthenaKernel/StreamLogger.h b/Control/AthenaKernel/AthenaKernel/StreamLogger.h deleted file mode 100644 index c9bf0d5fed0..00000000000 --- a/Control/AthenaKernel/AthenaKernel/StreamLogger.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration -*/ - -#ifndef ATHENAKERNEL_STREAMLOGGER_H -#define ATHENAKERNEL_STREAMLOGGER_H 1 - -/** - * @file StreamLogger.h - * @brief provide entry point for binding output streams. - * - * @author Charles Leggett - * $Id: StreamLogger.h,v 1.2 2007-06-14 01:57:23 calaf Exp $ - */ - -#include "GaudiKernel/MsgStream.h" - -#include <ostream> -#include <string> - -class IMessageSvc; - -/** - * @class StreamLogger - * @brief provide entry point for binding output streams. - * @details bind with - * @code - * boost::function<void (const std::string&)> streamLog; - * @endcode - * for MsgSvc: - * @code - * StreamLogger *logger = new StreamLogger(msgSvc(), MSG::LEVEL, MsgName); - * boost::bind(&StreamLogger::WriteToMsgSvc, logger, _1); - * @endcode - * for stderr, stdout, etc - * @code - * StreamLogger *logger = new StreamLogger(std::cerr); - * streamLog = boost::bind(&StreamLogger::WriteToStream, logger, _1) - * @endcode - * for file - * @code - * StreamLogger *logger = new StreamLogger(fileName); - * streamLog = boost::bind(&StreamLogger::WriteToStream, logger, _1); - * @endcode - * to write out: - * @code - * streamLog("output"); - * @endcode - */ -class StreamLogger { -public: - StreamLogger(const std::string& file); - StreamLogger(std::ostream &ost); - StreamLogger(IMessageSvc*, MSG::Level, - const std::string& msgName="StreamLogger"); - ~StreamLogger(); - - std::string name() const { return m_name; } - - void WriteToStream(const std::string& str) { *p_ost << str << std::endl; } - void WriteToMsgSvc(const std::string& str) { *p_msgStr << m_level << str - << endmsg; } - -private: - bool m_isMine; - std::ostream *p_ost; - MsgStream *p_msgStr; - MSG::Level m_level; - std::string m_name; -}; - - -#endif diff --git a/Control/AthenaKernel/AthenaKernel/errorcheck.h b/Control/AthenaKernel/AthenaKernel/errorcheck.h index 00e5cbb0bbc..01d4cb71fd3 100644 --- a/Control/AthenaKernel/AthenaKernel/errorcheck.h +++ b/Control/AthenaKernel/AthenaKernel/errorcheck.h @@ -17,7 +17,7 @@ *@code * StatusCode sc = something(); * if (! sc.isSuccess() ) { - * log << "Some error message" << endreq; + * log << "Some error message" << endmsg; * return sc; * } @endcode @@ -62,7 +62,7 @@ * error reporting provided here with the macro * @c REPORT_ERROR, which takes a @c StatusCode as an argument. * Additional text can be added with the output streaming operator, - * as for @c MsgStream. (No need to use @c endreq.) + * as for @c MsgStream. (No need to use @c endmsg.) * *@code * StatusCode sc = something(); diff --git a/Control/AthenaKernel/CMakeLists.txt b/Control/AthenaKernel/CMakeLists.txt index a62f120d48d..444b4172257 100644 --- a/Control/AthenaKernel/CMakeLists.txt +++ b/Control/AthenaKernel/CMakeLists.txt @@ -1,3 +1,4 @@ +# $Id: CMakeLists.txt 787829 2016-12-02 10:10:58Z krasznaa $ ################################################################################ # Package: AthenaKernel ################################################################################ @@ -6,93 +7,86 @@ atlas_subdir( AthenaKernel ) # Declare the package's dependencies: -atlas_depends_on_subdirs( PUBLIC - Control/CxxUtils - Control/DataModelRoot - GaudiKernel - Tools/Scripts - PRIVATE - AtlasTest/TestTools ) +atlas_depends_on_subdirs( + PUBLIC + Control/CxxUtils + Control/DataModelRoot + GaudiKernel + PRIVATE + AtlasTest/TestTools ) # External dependencies: -find_package( Boost COMPONENTS program_options regex filesystem system thread ) -find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) +find_package( Boost COMPONENTS program_options regex filesystem thread ) +find_package( ROOT COMPONENTS Core ) find_package( UUID ) -# Component(s) in the package: +# Only link agains the RT library on Linux: +set( rt_library ) +if( UNIX AND NOT APPLE ) + set( rt_library rt ) +endif() + +# Libraries in the package: atlas_add_library( AthenaKernel - src/*.cxx - PUBLIC_HEADERS AthenaKernel - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel rt - PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} TestTools ) + AthenaKernel/*.h AthenaKernel/*.icc src/*.cxx + PUBLIC_HEADERS AthenaKernel + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot + GaudiKernel ${rt_library} + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ) atlas_add_dictionary( AthenaKernelDict - AthenaKernel/AthenaKernelDict.h - AthenaKernel/selection.xml - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} rt CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel ) + AthenaKernel/AthenaKernelDict.h + AthenaKernel/selection.xml + LINK_LIBRARIES GaudiKernel AthenaKernel ) +# Test(s) in the package: atlas_add_test( getMessageSvc_test - SOURCES - test/getMessageSvc_test.cxx - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel - EXTRA_PATTERNS "^=========+|^ApplicationMgr +SUCCESS|^HistogramPersis.*INFO.*CnvServices|^StatusCodeSvc +INFO initialize|^ *Welcome to ApplicationMgr|^ *running on|^Wall clock time" ) + SOURCES test/getMessageSvc_test.cxx + LINK_LIBRARIES GaudiKernel TestTools AthenaKernel + EXTRA_PATTERNS "^=========+|^ApplicationMgr +SUCCESS|^HistogramPersis.*INFO.*CnvServices|^StatusCodeSvc +INFO initialize|^ *Welcome to ApplicationMgr|^ *running on|^Wall clock time" ) atlas_add_test( MsgStreamMember_test - SOURCES - test/MsgStreamMember_test.cxx - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel - EXTRA_PATTERNS "^=========+|^ApplicationMgr +SUCCESS|^HistogramPersis.*INFO.*CnvServices|^StatusCodeSvc +INFO initialize|^ *Welcome to ApplicationMgr|^ *running on|^Wall clock time |ref count" ) + SOURCES test/MsgStreamMember_test.cxx + LINK_LIBRARIES TestTools AthenaKernel + EXTRA_PATTERNS "^=========+|^ApplicationMgr +SUCCESS|^HistogramPersis.*INFO.*CnvServices|^StatusCodeSvc +INFO initialize|^ *Welcome to ApplicationMgr|^ *running on|^Wall clock time |ref count" ) atlas_add_test( AthenaPackageInfo_test - SOURCES - test/AthenaPackageInfo_test.cxx - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel ) + SOURCES test/AthenaPackageInfo_test.cxx + LINK_LIBRARIES AthenaKernel ) atlas_add_test( DirSearchPath_test - SOURCES - test/DirSearchPath_test.cxx - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel ) + SOURCES test/DirSearchPath_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} GaudiKernel ) atlas_add_test( Chrono_test - SOURCES - test/Chrono_test.cxx - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel ) + SOURCES test/Chrono_test.cxx + LINK_LIBRARIES GaudiKernel AthenaKernel ) atlas_add_test( errorcheck_test - SOURCES - test/errorcheck_test.cxx - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel - EXTRA_PATTERNS "^=========+|^ApplicationMgr +SUCCESS|^HistogramPersis.*INFO.*CnvServices|^StatusCodeSvc +INFO initialize|^ *Welcome to ApplicationMgr|^ *running on|^Wall clock time" ) + SOURCES test/errorcheck_test.cxx + LINK_LIBRARIES GaudiKernel TestTools AthenaKernel + EXTRA_PATTERNS "^=========+|^ApplicationMgr +SUCCESS|^HistogramPersis.*INFO.*CnvServices|^StatusCodeSvc +INFO initialize|^ *Welcome to ApplicationMgr|^ *running on|^Wall clock time" ) atlas_add_test( type_tools_test - SOURCES - test/type_tools_test.cxx - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel ) + SOURCES test/type_tools_test.cxx + LINK_LIBRARIES AthenaKernel ) atlas_add_test( Units_test - SOURCES - test/Units_test.cxx - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel ) + SOURCES test/Units_test.cxx + LINK_LIBRARIES GaudiKernel TestTools AthenaKernel ) atlas_add_test( DataObjectSharedPtr_test - SOURCES - test/DataObjectSharedPtr_test.cxx - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel ) + SOURCES test/DataObjectSharedPtr_test.cxx + LINK_LIBRARIES AthenaKernel ) -atlas_add_executable( genCLIDDB - utils/genCLIDDB.cxx - INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} - LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} ${UUID_LIBRARIES} CxxUtils DataModelRoot GaudiKernel TestTools AthenaKernel ) +atlas_add_test( IRCUSvc_test + SOURCES test/IRCUSvc_test.cxx + LINK_LIBRARIES AthenaKernel ) +atlas_add_test( RCUObject_test + SOURCES test/RCUObject_test.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} AthenaKernel ) diff --git a/Control/AthenaKernel/cmt/requirements b/Control/AthenaKernel/cmt/requirements index d0edbb3f2d4..b741604af75 100644 --- a/Control/AthenaKernel/cmt/requirements +++ b/Control/AthenaKernel/cmt/requirements @@ -45,14 +45,12 @@ apply_pattern UnitTest_run unit_test=errorcheck extrapatterns="'$(extrapatterns) apply_pattern UnitTest_run unit_test=type_tools apply_pattern UnitTest_run unit_test=Units apply_pattern UnitTest_run unit_test=DataObjectSharedPtr +apply_pattern UnitTest_run unit_test=IRCUSvc +apply_pattern UnitTest_run unit_test=RCUObject macro_append DOXYGEN_INPUT " ../doc ../test ../AthenaKernel/tools " macro_append DOXYGEN_FILE_PATTERNS " *.icc" -application genCLIDDB ../utils/genCLIDDB.cxx -macro_append genCLIDDBlinkopts " $(Boost_linkopts_program_options) " -macro_append genCLIDDB_dependencies " AthenaKernel" - # # dictionary creation for UserDataAssociation # diff --git a/Control/AthenaKernel/share/IRCUSvc_test.ref b/Control/AthenaKernel/share/IRCUSvc_test.ref new file mode 100644 index 00000000000..a5bce3fd256 --- /dev/null +++ b/Control/AthenaKernel/share/IRCUSvc_test.ref @@ -0,0 +1 @@ +test1 diff --git a/Control/AthenaKernel/share/RCUObject_test.ref b/Control/AthenaKernel/share/RCUObject_test.ref new file mode 100644 index 00000000000..76983460f7f --- /dev/null +++ b/Control/AthenaKernel/share/RCUObject_test.ref @@ -0,0 +1,3 @@ +test1 +test2 +test3 diff --git a/Control/AthenaKernel/src/IClassIDSvc.cxx b/Control/AthenaKernel/src/IClassIDSvc.cxx deleted file mode 100644 index 95c79b4cc99..00000000000 --- a/Control/AthenaKernel/src/IClassIDSvc.cxx +++ /dev/null @@ -1,49 +0,0 @@ -///////////////////////// -*- C++ -*- ///////////////////////////// - -/* - Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration -*/ - -// IClassIDSvc.cxx -// Implementation file for class IClassIDSvc -// Author: S.Binet<binet@cern.ch> -/////////////////////////////////////////////////////////////////// - -// AthenaKernel includes -#include "AthenaKernel/IClassIDSvc.h" - - - -/////////////////////////////////////////////////////////////////// -// Public methods: -/////////////////////////////////////////////////////////////////// - -// Constructors -//////////////// - -// Destructor -/////////////// -IClassIDSvc::~IClassIDSvc() -{} - -/////////////////////////////////////////////////////////////////// -// Const methods: -/////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////// -// Non-const methods: -/////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////// -// Protected methods: -/////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////// -// Const methods: -/////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////// -// Non-const methods: -/////////////////////////////////////////////////////////////////// - - diff --git a/Control/AthenaKernel/src/RCUObject.cxx b/Control/AthenaKernel/src/RCUObject.cxx new file mode 100644 index 00000000000..b46fd9cd07e --- /dev/null +++ b/Control/AthenaKernel/src/RCUObject.cxx @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file AthenaKernel/src/RCUObject.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief read-copy-update (RCU) style synchronization for Athena. + */ + + +#include "AthenaKernel/RCUObject.h" +#include "AthenaKernel/IRCUSvc.h" +#include <cstdlib> + + +namespace Athena { + + +/** + * @brief Constructor, with RCUSvc. + * @param svc Service with which to register. + * + * The service will call @c quiescent at the end of each event. + */ +IRCUObject::IRCUObject (IRCUSvc& svc) + : m_svc (&svc), + m_grace (svc.getNumSlots()) +{ +} + + +/** + * @brief Constructor, with event slot count. + * @param nslots Number of active event slots. + * + * This version does not register with a service. + */ +IRCUObject::IRCUObject (size_t nslots) + : m_svc (nullptr), + m_grace (nslots) +{ +} + + +/** + * @brief Destructor. + * + * Remove this object from the service if it has been registered. + */ +IRCUObject::~IRCUObject() +{ + if (m_svc && m_svc->remove (this).isFailure()) + std::abort(); +} + + +} // namespace Athena diff --git a/Control/AthenaKernel/src/StreamLogger.cxx b/Control/AthenaKernel/src/StreamLogger.cxx deleted file mode 100644 index a7c04f583ad..00000000000 --- a/Control/AthenaKernel/src/StreamLogger.cxx +++ /dev/null @@ -1,68 +0,0 @@ -/* - Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration -*/ - -#include "AthenaKernel/StreamLogger.h" - -#include "GaudiKernel/IMessageSvc.h" - -#include <stdexcept> -#include <fstream> - -///////////////////////////////////////////////////////////////////////////// -// -// Constructor for a file - -StreamLogger::StreamLogger(const std::string& file): m_isMine(1), - p_ost(0), p_msgStr(0), - m_level (MSG::INFO) -{ - m_name = "file:" + file; - p_ost = new std::ofstream(file.c_str()); - if (p_ost == 0) { - throw std::invalid_argument("can't open file"); - } -} - -///////////////////////////////////////////////////////////////////////////// -// -// Constructor for MsgStream - -StreamLogger::StreamLogger(IMessageSvc *svc, MSG::Level lev, - const std::string& msgName): - m_isMine(1), p_ost(0), p_msgStr(0) { - p_msgStr = new MsgStream( svc, msgName); - m_level = lev; - m_name = "MsgStream"; -} - -///////////////////////////////////////////////////////////////////////////// -// -// Constructor for an ostream - -StreamLogger::StreamLogger(std::ostream& ost): m_isMine(0) , p_ost(0), - p_msgStr(0), - m_level (MSG::INFO) -{ - p_ost = &ost; - if (&ost == &std::cerr) { - m_name = "STDERR"; - } else if ( &ost == &std::cout) { - m_name = "STDOUT"; - } else { - m_name = "unknown ostream"; - } -} - -///////////////////////////////////////////////////////////////////////////// -// -// Destructor - -StreamLogger::~StreamLogger() { - if (m_isMine && p_ost != 0) { - delete p_ost; - } - if (p_msgStr != 0) { - delete p_msgStr; - } -} diff --git a/Control/AthenaKernel/test/IRCUSvc_test.cxx b/Control/AthenaKernel/test/IRCUSvc_test.cxx new file mode 100644 index 00000000000..c376a7c7f03 --- /dev/null +++ b/Control/AthenaKernel/test/IRCUSvc_test.cxx @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file IRCUOSVC_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief Regression tests for RCUObject. + */ + +#undef NDEBUG + +#include "AthenaKernel/IRCUSvc.h" +#include <cassert> +#include <iostream> +#include <cstdlib> + + +using Athena::IRCUSvc; +using Athena::IRCUObject; +using Athena::RCUObject; +using Athena::RCURead; + + +class TestRCUSvc + : public IRCUSvc +{ +public: + virtual StatusCode remove (IRCUObject* /*obj*/) override { return StatusCode::SUCCESS; } + virtual size_t getNumSlots() const override { return 1; } + virtual void add (IRCUObject* obj) override + { m_added = obj; } + + virtual unsigned long addRef() override { std::abort(); } + virtual unsigned long release() override { std::abort(); } + virtual StatusCode queryInterface(const InterfaceID &/*ti*/, void** /*pp*/) override { std::abort(); } + + IRCUObject* m_added = nullptr; +}; + + +struct Payload +{ + Payload (int a, int b) : + m_a(a), m_b(b) + {} + Payload& operator= (const Payload&) = default; + + int m_a; + int m_b; +}; + + +void test1() +{ + std::cout << "test1\n"; + TestRCUSvc svc; + assert (svc.m_added == nullptr); + std::unique_ptr<RCUObject<Payload> > obj = svc.newrcu<Payload> (10, 20); + RCURead<Payload> r (*obj); + assert (r->m_a == 10); + assert (r->m_b == 20); + assert (svc.m_added == obj.get()); +} + + +int main() +{ + test1(); + return 0; +} diff --git a/Control/AthenaKernel/test/RCUObject_test.cxx b/Control/AthenaKernel/test/RCUObject_test.cxx new file mode 100644 index 00000000000..fa78f31619f --- /dev/null +++ b/Control/AthenaKernel/test/RCUObject_test.cxx @@ -0,0 +1,265 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id$ +/** + * @file RCUObject_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Aug, 2016 + * @brief Regression tests for RCUObject. + */ + +#undef NDEBUG + +#include "AthenaKernel/RCUObject.h" +#include "AthenaKernel/IRCUSvc.h" +#include "boost/thread/shared_mutex.hpp" +#include "boost/thread/shared_lock_guard.hpp" +#include <cassert> +#include <iostream> +#include <thread> +#include <mutex> +#include <atomic> + + +using Athena::IRCUObject; +using Athena::RCUObject; +using Athena::IRCUSvc; +using Athena::RCURead; +using Athena::RCUReadQuiesce; +using Athena::RCUUpdate; + + +const int nslots = 4; + + +class TestRCUSvc + : public IRCUSvc +{ +public: + virtual StatusCode remove (IRCUObject* obj) override + { + m_removed = obj; + return StatusCode::SUCCESS; + } + virtual size_t getNumSlots() const override + { return nslots; } + virtual void add (IRCUObject* /*obj*/) override + { } + + virtual unsigned long addRef() override { std::abort(); } + virtual unsigned long release() override { std::abort(); } + virtual StatusCode queryInterface(const InterfaceID &/*ti*/, void** /*pp*/) override { std::abort(); } + + IRCUObject* m_removed = nullptr; +}; + + +struct Payload +{ + Payload (int x=0) + : a(x), b(x), c(x), d(x) + { + ++ninstance; + } + Payload& operator= (const Payload&) = default; + ~Payload() + { + --ninstance; + if (dolog) { + std::lock_guard<std::mutex> g (m_mutex); + m_dlog.push_back(a); + } + } + static + std::vector<int> getlog() + { + std::lock_guard<std::mutex> g (m_mutex); + std::vector<int> log; + log.swap (m_dlog); + return log; + } + void check(int x) const + { + assert (a == x); + assert (b == x); + assert (c == x); + assert (d == x); + } + void check() const + { + check(a); + } + int a, b, c, d; + + static std::atomic<int> ninstance; + static bool dolog; + +private: + static std::vector<int> m_dlog; + static std::mutex m_mutex; +}; + +std::atomic<int> Payload::ninstance; +bool Payload::dolog = true; +std::vector<int> Payload::m_dlog; +std::mutex Payload::m_mutex; + + +void test1() +{ + std::cout << "test1\n"; + + TestRCUSvc svc; + { + RCUObject<Payload>* optr = nullptr; + { + RCUObject<Payload> rcuo (svc, 3); + RCURead<Payload> r (rcuo); + r->check(3); + + optr = &rcuo; + assert (svc.m_removed == nullptr); + } + assert (svc.m_removed == optr); + } + Payload::getlog(); +} + + +void test2() +{ + std::cout << "test2\n"; + TestRCUSvc svc; + + + RCUObject<Payload> rcuo (svc); + { + RCURead<Payload> r (rcuo); + r->check(0); + } + { + EventContext ctx (0, 1); + RCUUpdate<Payload> u (rcuo, ctx); + u->check(0); + u.update (std::make_unique<Payload> (2)); + u->check(2); + } + { + RCURead<Payload> r (rcuo); + r->check(2); + } + { + EventContext ctx (0, 2); + RCUReadQuiesce<Payload> r (rcuo, ctx); + r->check(2); + } + assert (Payload::getlog().empty()); + rcuo.quiescent (EventContext (0, 0)); + assert (Payload::getlog().empty()); + Gaudi::Hive::setCurrentContextId(3); + rcuo.quiescent (); + assert (Payload::getlog() == std::vector<int>{0}); +} + + +class ThreadedTest +{ +public: + ThreadedTest (TestRCUSvc& svc); + void runtest(); + + struct testThread + { + testThread (ThreadedTest& test, int iworker) + : m_test(test), m_iworker(iworker) {} + void operator()(); + + ThreadedTest& m_test; + int m_iworker; + }; + +private: + boost::shared_mutex m_sm; + RCUObject<Payload> m_rcuobj; +}; + + +ThreadedTest::ThreadedTest (TestRCUSvc& svc) + : m_rcuobj(svc) +{ +} + +void ThreadedTest::runtest() +{ + std::thread threads[nslots]; + m_sm.lock(); + for (int i=0; i < nslots; i++) + threads[i] = std::thread (testThread (*this, i)); + // Try to get the threads starting as much at the same time as possible. + m_sm.unlock(); + for (int i=0; i < nslots; i++) + threads[i].join(); + for (int i=0; i < nslots; i++) + m_rcuobj.quiescent (EventContext (0, i)); +} + + +void ThreadedTest::testThread::operator()() +{ + boost::shared_lock_guard<boost::shared_mutex> guard (m_test.m_sm); + Gaudi::Hive::setCurrentContextId (m_iworker); + + for (int i=0; i < 10000; i++) { + if (i%5 == 0) { + auto r = m_test.m_rcuobj.reader(); + r->check(); + } + else if (i%29 == 0) { + if (i%2 == 0) { + auto r = m_test.m_rcuobj.readerQuiesce (EventContext (0, m_iworker)); + r->check(); + } + else { + auto r = m_test.m_rcuobj.readerQuiesce(); + r->check(); + } + } + else if (i%17 == 0) { + EventContext ctx (0, m_iworker); + RCUObject<Payload>::Update_t u (m_test.m_rcuobj, ctx); + u.update (std::make_unique<Payload> (u->a)); + } + + if (i%13 == 0) + m_test.m_rcuobj.quiescent (EventContext (0, m_iworker)); + } +} + + +void test3() +{ + std::cout << "test3\n"; + + Payload::dolog = false; + assert (Payload::ninstance == 0); + { + TestRCUSvc svc; + ThreadedTest test (svc); + for (int i=0; i < 1000; i++) + test.runtest(); + assert (Payload::ninstance == 1); + } + assert (Payload::ninstance == 0); +} + + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} + diff --git a/Control/AthenaKernel/test/errorcheck_test.cxx b/Control/AthenaKernel/test/errorcheck_test.cxx index 1e74c90adf3..a57eac03b8c 100644 --- a/Control/AthenaKernel/test/errorcheck_test.cxx +++ b/Control/AthenaKernel/test/errorcheck_test.cxx @@ -163,7 +163,7 @@ StatusCode test1() msg << "a... "; msg << "b"; } - REPORT_MESSAGE_WITH_CONTEXT (MSG::INFO, "alg") << "foo" << endreq; + REPORT_MESSAGE_WITH_CONTEXT (MSG::INFO, "alg") << "foo" << endmsg; assert( test1a().isFailure() ); assert( test1b().isFailure() ); assert( test1c().isFailure() ); @@ -195,7 +195,7 @@ void test2 (std::vector<int> = std::vector<int>(), int (*)() = 0, int [] = 0) { - REPORT_MESSAGE_WITH_CONTEXT (MSG::INFO, "test2") << "test2" << endreq; + REPORT_MESSAGE_WITH_CONTEXT (MSG::INFO, "test2") << "test2" << endmsg; assert (errorcheck::clean_allocator ("void test2(std::vector<int, std::allocator<int> >, const int*, int (*)(), int*)") == "void test2(std::vector<int>, const int*, int (*)(), int*)"); @@ -204,7 +204,7 @@ void test2 (std::vector<int> = std::vector<int>(), void test3 (const std::string& = "", int = 0) { - REPORT_MESSAGE_WITH_CONTEXT (MSG::INFO, "test3") << "test3" << endreq; + REPORT_MESSAGE_WITH_CONTEXT (MSG::INFO, "test3") << "test3" << endmsg; } diff --git a/Control/AthenaKernel/utils/genCLIDDB.cxx b/Control/AthenaKernel/utils/genCLIDDB.cxx deleted file mode 100644 index ff9970d4fae..00000000000 --- a/Control/AthenaKernel/utils/genCLIDDB.cxx +++ /dev/null @@ -1,138 +0,0 @@ -/* - Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration -*/ - - -#include <cassert> -#include <exception> -#include <iostream> -#include <string> -#include "TestTools/initGaudi.h" -#include "GaudiKernel/IClassManager.h" -#include "GaudiKernel/IProperty.h" -#include "GaudiKernel/ISvcLocator.h" -#include "GaudiKernel/SmartIF.h" -#include "AthenaKernel/IClassIDSvc.h" -#ifdef ATLAS_CMAKE -#include <dlfcn.h> -#endif - -#include <boost/program_options.hpp> -namespace po = boost::program_options; - -using namespace std; -using namespace Athena_test; - -int inputError(std::string errDescr, const po::options_description& optDescr ) { - cerr << errDescr << "\n" << optDescr << endl; - return 1; -} -int gaudiError(std::string errDescr) { - cerr << errDescr << endl; - return 2; -} - -int main(int argc, char* argv[]) { - // Declare the supported options. - po::options_description desc("clidDB_gen allowed options"); - desc.add_options() - ("help,h", "produce help message") - ("package,p", po::value<string>(), "package we want to load clids from") - ("input,i", po::value<string>(), "optional path to input clid db file") - ("output,o", po::value<string>(), "optional path to resulting clid db file") - ("jobopts,j", po::value<string>(), "name of optional job options txt file, located at ../share/jobopts") - ; - string packageName("ALL"); - string inputCLIDDB; - string outFileName; - - po::variables_map vm; - try { - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - } catch (const exception& e) { - return inputError(e.what(), desc); - } - - if (vm.count("help")) { - cout << desc << endl; - return 0; - } - - if (vm.count("package")) { - cout << "Generating clid.db for package " - << vm["package"].as<string>() << ".\n"; - packageName = vm["package"].as<string>(); - } else { - return inputError("Please specify a package using option --package.\n", - desc); - } - - if (vm.count("output")) { - outFileName = vm["output"].as<string>(); - } else { - outFileName = packageName + "_clid.db"; - } - cout << "Resulting clid.db will be written to " - << outFileName << ".\n"; - - ISvcLocator* pSvcLoc(0); - if (vm.count("jobopts")) { - if (!initGaudi(vm["jobopts"].as<string>(), pSvcLoc)) { - return gaudiError("clidDB_gen can not run"); - } - } else { - if (!initGaudi(pSvcLoc)) { - return gaudiError("clidDB_gen can not run"); - } - } - if ( 0 == pSvcLoc ) { - return gaudiError( "NULL pointer to ISvcLocator" ); - } - SmartIF<IClassManager> pICM(pSvcLoc); - if (!pICM.isValid()) { - gaudiError("can not get IClassManager"); - } - -#ifdef ATLAS_CMAKE - dlopen("libCLIDComps.so", RTLD_LAZY); -#endif - IClassIDSvc* pClassIDSvc(0); - if (!(pSvcLoc->service("ClassIDSvc", pClassIDSvc, true).isSuccess())) { - cerr << "can not get ClassIDSvc, no clid.db will be generated" << endl; - return 0; - } - if ( 0 == pClassIDSvc ) { - return gaudiError("NULL pointer to IClassIDSvc"); - } - - IProperty *pCLIDSvcProp(dynamic_cast<IProperty*>(pClassIDSvc)); - if ( 0 == pCLIDSvcProp ) { - return gaudiError("NULL pointer to IClassIDSvc's property"); - } - - if (vm.count("input")) { - cout << "Reading clid.db from " - << vm["input"].as<string>() << ".\n"; - if (!(pCLIDSvcProp->setProperty( "CLIDDBFiles", - "{\"" + vm["input"].as<string>() + "\"}" )).isSuccess()) { - return inputError("Error setting ClassIDSvc.CLIDDBFiles to " - + vm["input"].as<string>(), - desc); - } - } - - pCLIDSvcProp->setProperty( "OutputFileName", outFileName ); - - if (!pICM->loadModule(packageName).isSuccess()) { - return gaudiError("can not load module " + packageName); - } - - //fill clid db - if (!(pClassIDSvc->reinitialize()).isSuccess()) { - return gaudiError("can not reinitialize ClassIDSvc"); - } - - //write out merged clid db on service finalize - return (pClassIDSvc->finalize()).isSuccess() ? 0 : -1; -} -- GitLab