Skip to content
Snippets Groups Projects
Commit 1f7335fd authored by Nat Goodspeed's avatar Nat Goodspeed
Browse files

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.
parent 794072c1
No related branches found
No related tags found
No related merge requests found
......@@ -247,6 +247,7 @@ set(llcommon_HEADER_FILES
llwin32headers.h
llwin32headerslean.h
llworkerthread.h
lockstatic.h
stdtypes.h
stringize.h
timer.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 @@ class LLInstanceTracker :
/*****************************************************************************
* 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:
/**
......
/**
* @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) */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment