diff options
| author | Nat Goodspeed <nat@lindenlab.com> | 2019-12-03 20:44:26 -0500 | 
|---|---|---|
| committer | Nat Goodspeed <nat@lindenlab.com> | 2020-03-25 15:28:17 -0400 | 
| commit | 1f7335fde34abdb9889e0c7b437fc02870570fcf (patch) | |
| tree | e777146b49b4f0a13f642c9d7914e25ba42bc713 | |
| parent | 794072c1415e986b95cab65f8217857263d7468a (diff) | |
DRTVWR-494: Extract LockStatic as a standalone template class.
The pattern of requiring a lock to permit *any* access to a static instance of
something seems generally useful. Break out lockstatic.h; recast
LLInstanceTracker to use it.
Moving LockStatic to an external template class instead of a nested class in
LLInstanceTrackerBase leaves LLInstanceTrackerBase pretty empty. Get rid of it.
And *that* means we can move the definition of the StaticData used by each
LLInstanceTracker specialization into the class itself, rather than having to
define it beforehand in namespace LLInstanceTrackerStuff.
| -rw-r--r-- | indra/llcommon/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | indra/llcommon/llinstancetracker.h | 98 | ||||
| -rw-r--r-- | indra/llcommon/lockstatic.h | 56 | 
3 files changed, 75 insertions, 80 deletions
| diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index af41b9e460..98e1c00ce3 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -247,6 +247,7 @@ set(llcommon_HEADER_FILES      llwin32headers.h      llwin32headerslean.h      llworkerthread.h +    lockstatic.h      stdtypes.h      stringize.h      timer.h diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 272ad8086e..cfb40c25f0 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -41,64 +41,20 @@  #include <boost/iterator/indirect_iterator.hpp>  #include <boost/iterator/filter_iterator.hpp> +#include "lockstatic.h" +  /***************************************************************************** -*   LLInstanceTrackerBase +*   StaticBase  *****************************************************************************/ -/** - * Base class manages "class-static" data that must actually have singleton - * semantics: one instance per process, rather than one instance per module as - * sometimes happens with data simply declared static. - */  namespace LLInstanceTrackerStuff  {      struct StaticBase      {          // We need to be able to lock static data while manipulating it. -        typedef std::mutex mutex_t; -        mutex_t mMutex; +        std::mutex mMutex;      };  } // namespace LLInstanceTrackerStuff -template <class Static> -class LL_COMMON_API LLInstanceTrackerBase -{ -protected: -    typedef Static StaticData; - -    // Instantiate this class to obtain a pointer to the canonical static -    // instance of class Static while holding a lock on that instance. Use of -    // Static::mMutex presumes either that Static is derived from StaticBase, -    // or that Static declares some other suitable mMutex. -    class LockStatic -    { -        typedef std::unique_lock<decltype(Static::mMutex)> lock_t; -    public: -        LockStatic(): -            mData(getStatic()), -            mLock(mData->mMutex) -        {} -        Static* get() const { return mData; } -        operator Static*() const { return get(); } -        Static* operator->() const { return get(); } -        // sometimes we must explicitly unlock... -        void unlock() -        { -            // but once we do, access is no longer permitted -            mData = nullptr; -            mLock.unlock(); -        } -    protected: -        Static* mData; -        lock_t mLock; -    private: -        Static* getStatic() -        { -            static Static sData; -            return &sData; -        } -    }; -}; -  /*****************************************************************************  *   LLInstanceTracker with key  *****************************************************************************/ @@ -108,29 +64,20 @@ enum EInstanceTrackerAllowKeyCollisions      LLInstanceTrackerReplaceOnCollision  }; -namespace LLInstanceTrackerStuff -{ -    template <typename KEY, typename VALUE> -    struct StaticMap: public StaticBase -    { -        typedef std::map<KEY, VALUE> InstanceMap; -        InstanceMap mMap; -    }; -} // LLInstanceTrackerStuff -  /// This mix-in class adds support for tracking all instances of the specified class parameter T  /// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup  /// If KEY is not provided, then instances are stored in a simple set  /// @NOTE: see explicit specialization below for default KEY==void case  template<typename T, typename KEY = void,           EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR = LLInstanceTrackerErrorOnCollision> -class LLInstanceTracker : -    public LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticMap<KEY, std::shared_ptr<T>>> +class LLInstanceTracker  { -    typedef LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticMap<KEY, std::shared_ptr<T>>> super; -    using typename super::StaticData; -    using typename super::LockStatic; -    typedef typename StaticData::InstanceMap InstanceMap; +    typedef std::map<KEY, std::shared_ptr<T>> InstanceMap; +    struct StaticData: public LLInstanceTrackerStuff::StaticBase +    { +        InstanceMap mMap; +    }; +    typedef llthread::LockStatic<StaticData> LockStatic;  public:      // snapshot of std::pair<const KEY, std::shared_ptr<T>> pairs @@ -334,16 +281,6 @@ private:  /*****************************************************************************  *   LLInstanceTracker without key  *****************************************************************************/ -namespace LLInstanceTrackerStuff -{ -    template <typename VALUE> -    struct StaticSet: public StaticBase -    { -        typedef std::set<VALUE> InstanceSet; -        InstanceSet mSet; -    }; -} // LLInstanceTrackerStuff -  // TODO:  // - For the case of omitted KEY template parameter, consider storing  //   std::map<T*, std::shared_ptr<T>> instead of std::set<std::shared_ptr<T>>. @@ -359,13 +296,14 @@ namespace LLInstanceTrackerStuff  /// explicit specialization for default case where KEY is void  /// use a simple std::set<T*>  template<typename T, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR> -class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR> : -    public LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticSet<std::shared_ptr<T>>> +class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR>  { -    typedef LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticSet<std::shared_ptr<T>>> super; -    using typename super::StaticData; -    using typename super::LockStatic; -    typedef typename StaticData::InstanceSet InstanceSet; +    typedef std::set<std::shared_ptr<T>> InstanceSet; +    struct StaticData: public LLInstanceTrackerStuff::StaticBase +    { +        InstanceSet mSet; +    }; +    typedef llthread::LockStatic<StaticData> LockStatic;  public:      /** diff --git a/indra/llcommon/lockstatic.h b/indra/llcommon/lockstatic.h new file mode 100644 index 0000000000..5f08742cae --- /dev/null +++ b/indra/llcommon/lockstatic.h @@ -0,0 +1,56 @@ +/** + * @file   lockstatic.h + * @author Nat Goodspeed + * @date   2019-12-03 + * @brief  LockStatic class provides mutex-guarded access to the specified + *         static data. + *  + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Copyright (c) 2019, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LOCKSTATIC_H) +#define LL_LOCKSTATIC_H + +#include "mutex.h"                  // std::unique_lock + +namespace llthread +{ + +// Instantiate this template to obtain a pointer to the canonical static +// instance of Static while holding a lock on that instance. Use of +// Static::mMutex presumes that Static declares some suitable mMutex. +template <typename Static> +class LockStatic +{ +    typedef std::unique_lock<decltype(Static::mMutex)> lock_t; +public: +    LockStatic(): +        mData(getStatic()), +        mLock(mData->mMutex) +    {} +    Static* get() const { return mData; } +    operator Static*() const { return get(); } +    Static* operator->() const { return get(); } +    // sometimes we must explicitly unlock... +    void unlock() +    { +        // but once we do, access is no longer permitted +        mData = nullptr; +        mLock.unlock(); +    } +protected: +    Static* mData; +    lock_t mLock; +private: +    Static* getStatic() +    { +        static Static sData; +        return &sData; +    } +}; + +} // llthread namespace + +#endif /* ! defined(LL_LOCKSTATIC_H) */ | 
