SH-3468 WIP add memory tracking base class
fixed crash on exit by making LLInstanceTracker iterators use atomic iterator nesting count for thread safetymaster
parent
013f04cabe
commit
3fd640a6e3
|
|
@ -29,6 +29,7 @@
|
|||
#include "linden_common.h"
|
||||
#include "llapr.h"
|
||||
#include "apr_dso.h"
|
||||
#include "llthreadlocalpointer.h"
|
||||
|
||||
apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
|
||||
LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
#include "apr_atomic.h"
|
||||
|
||||
#include "llstring.h"
|
||||
#include "llinstancetracker.h"
|
||||
|
||||
extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
|
||||
extern apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
|
|
@ -170,14 +169,17 @@ public:
|
|||
LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
|
||||
~LLAtomic32<Type>() {};
|
||||
|
||||
operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
|
||||
operator const Type() { return get(); }
|
||||
Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
|
||||
void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
|
||||
void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
|
||||
Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
|
||||
Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
|
||||
Type operator ++() { apr_atomic_inc32(&mData); return get(); } // ++Type
|
||||
Type operator --(int) { const Type result(get()); apr_atomic_dec32(&mData); return result; } // Type--
|
||||
Type operator --() { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
|
||||
|
||||
private:
|
||||
const Type get() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
|
||||
apr_uint32_t mData;
|
||||
};
|
||||
|
||||
|
|
@ -262,134 +264,5 @@ public:
|
|||
//*******************************************************************************************************************************
|
||||
};
|
||||
|
||||
class LLThreadLocalPointerBase : public LLInstanceTracker<LLThreadLocalPointerBase>
|
||||
{
|
||||
public:
|
||||
LLThreadLocalPointerBase()
|
||||
: mThreadKey(NULL)
|
||||
{
|
||||
if (sInitialized)
|
||||
{
|
||||
initStorage();
|
||||
}
|
||||
}
|
||||
|
||||
LLThreadLocalPointerBase( const LLThreadLocalPointerBase& other)
|
||||
: mThreadKey(NULL)
|
||||
{
|
||||
if (sInitialized)
|
||||
{
|
||||
initStorage();
|
||||
}
|
||||
}
|
||||
|
||||
~LLThreadLocalPointerBase()
|
||||
{
|
||||
destroyStorage();
|
||||
}
|
||||
|
||||
static void initAllThreadLocalStorage();
|
||||
static void destroyAllThreadLocalStorage();
|
||||
|
||||
protected:
|
||||
void set(void* value);
|
||||
|
||||
LL_FORCE_INLINE void* get()
|
||||
{
|
||||
// llassert(sInitialized);
|
||||
void* ptr;
|
||||
apr_status_t result =
|
||||
apr_threadkey_private_get(&ptr, mThreadKey);
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
ll_apr_warn_status(result);
|
||||
llerrs << "Failed to get thread local data" << llendl;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE const void* get() const
|
||||
{
|
||||
void* ptr;
|
||||
apr_status_t result =
|
||||
apr_threadkey_private_get(&ptr, mThreadKey);
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
ll_apr_warn_status(result);
|
||||
llerrs << "Failed to get thread local data" << llendl;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void initStorage();
|
||||
void destroyStorage();
|
||||
|
||||
protected:
|
||||
apr_threadkey_t* mThreadKey;
|
||||
static bool sInitialized;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class LLThreadLocalPointer : public LLThreadLocalPointerBase
|
||||
{
|
||||
public:
|
||||
|
||||
LLThreadLocalPointer()
|
||||
{}
|
||||
|
||||
explicit LLThreadLocalPointer(T* value)
|
||||
{
|
||||
set(value);
|
||||
}
|
||||
|
||||
|
||||
LLThreadLocalPointer(const LLThreadLocalPointer<T>& other)
|
||||
: LLThreadLocalPointerBase(other)
|
||||
{
|
||||
set(other.get());
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE T* get()
|
||||
{
|
||||
return (T*)LLThreadLocalPointerBase::get();
|
||||
}
|
||||
|
||||
const T* get() const
|
||||
{
|
||||
return (const T*)LLThreadLocalPointerBase::get();
|
||||
}
|
||||
|
||||
T* operator -> ()
|
||||
{
|
||||
return (T*)get();
|
||||
}
|
||||
|
||||
const T* operator -> () const
|
||||
{
|
||||
return (T*)get();
|
||||
}
|
||||
|
||||
T& operator*()
|
||||
{
|
||||
return *(T*)get();
|
||||
}
|
||||
|
||||
const T& operator*() const
|
||||
{
|
||||
return *(T*)get();
|
||||
}
|
||||
|
||||
LLThreadLocalPointer<T>& operator = (T* value)
|
||||
{
|
||||
set((void*)value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator ==(T* other)
|
||||
{
|
||||
if (!sInitialized) return false;
|
||||
return get() == other;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LL_LLAPR_H
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "llinstancetracker.h"
|
||||
#include "llapr.h"
|
||||
|
||||
// STL headers
|
||||
// std headers
|
||||
// external library headers
|
||||
|
|
@ -47,3 +49,19 @@ void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
|
|||
InstancesMap::mapped_type()))
|
||||
.first->second;
|
||||
}
|
||||
|
||||
void LLInstanceTrackerBase::StaticBase::incrementDepth()
|
||||
{
|
||||
apr_atomic_inc32(&sIterationNestDepth);
|
||||
}
|
||||
|
||||
void LLInstanceTrackerBase::StaticBase::decrementDepth()
|
||||
{
|
||||
apr_atomic_dec32(&sIterationNestDepth);
|
||||
}
|
||||
|
||||
U32 LLInstanceTrackerBase::StaticBase::getDepth()
|
||||
{
|
||||
apr_uint32_t data = apr_atomic_read32(&sIterationNestDepth);
|
||||
return data;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,12 @@ protected:
|
|||
StaticBase():
|
||||
sIterationNestDepth(0)
|
||||
{}
|
||||
S32 sIterationNestDepth;
|
||||
|
||||
void incrementDepth();
|
||||
void decrementDepth();
|
||||
U32 getDepth();
|
||||
private:
|
||||
U32 sIterationNestDepth;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -99,12 +104,12 @@ public:
|
|||
instance_iter(const typename InstanceMap::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
getStatic().incrementDepth();
|
||||
}
|
||||
|
||||
~instance_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
getStatic().decrementDepth();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -133,18 +138,18 @@ public:
|
|||
key_iter(typename InstanceMap::iterator it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
getStatic().incrementDepth();
|
||||
}
|
||||
|
||||
key_iter(const key_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
getStatic().incrementDepth();
|
||||
}
|
||||
|
||||
~key_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
getStatic().decrementDepth();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -203,7 +208,7 @@ protected:
|
|||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
llassert_always(getStatic().sIterationNestDepth == 0);
|
||||
llassert_always(getStatic().getDepth() == 0);
|
||||
remove_();
|
||||
}
|
||||
virtual void setKey(KEY key) { remove_(); add_(key); }
|
||||
|
|
@ -262,18 +267,18 @@ public:
|
|||
instance_iter(const typename InstanceSet::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
getStatic().incrementDepth();
|
||||
}
|
||||
|
||||
instance_iter(const instance_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
getStatic().incrementDepth();
|
||||
}
|
||||
|
||||
~instance_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
getStatic().decrementDepth();
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -306,7 +311,7 @@ protected:
|
|||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
llassert_always(getStatic().sIterationNestDepth == 0);
|
||||
llassert_always(getStatic().getDepth() == 0);
|
||||
getSet_().erase(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
#include <typeinfo>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,164 @@
|
|||
/**
|
||||
* @file llthreadlocalpointer.h
|
||||
* @author Richard
|
||||
* @brief Pointer class that manages a distinct value per thread
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLTHREADLOCALPOINTER_H
|
||||
#define LL_LLTHREADLOCALPOINTER_H
|
||||
|
||||
#include "llinstancetracker.h"
|
||||
#include "llapr.h"
|
||||
|
||||
class LLThreadLocalPointerBase : public LLInstanceTracker<LLThreadLocalPointerBase>
|
||||
{
|
||||
public:
|
||||
LLThreadLocalPointerBase()
|
||||
: mThreadKey(NULL)
|
||||
{
|
||||
if (sInitialized)
|
||||
{
|
||||
initStorage();
|
||||
}
|
||||
}
|
||||
|
||||
LLThreadLocalPointerBase( const LLThreadLocalPointerBase& other)
|
||||
: mThreadKey(NULL)
|
||||
{
|
||||
if (sInitialized)
|
||||
{
|
||||
initStorage();
|
||||
}
|
||||
}
|
||||
|
||||
~LLThreadLocalPointerBase()
|
||||
{
|
||||
destroyStorage();
|
||||
}
|
||||
|
||||
static void initAllThreadLocalStorage();
|
||||
static void destroyAllThreadLocalStorage();
|
||||
|
||||
protected:
|
||||
void set(void* value);
|
||||
|
||||
LL_FORCE_INLINE void* get()
|
||||
{
|
||||
// llassert(sInitialized);
|
||||
void* ptr;
|
||||
apr_status_t result =
|
||||
apr_threadkey_private_get(&ptr, mThreadKey);
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
ll_apr_warn_status(result);
|
||||
llerrs << "Failed to get thread local data" << llendl;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE const void* get() const
|
||||
{
|
||||
void* ptr;
|
||||
apr_status_t result =
|
||||
apr_threadkey_private_get(&ptr, mThreadKey);
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
ll_apr_warn_status(result);
|
||||
llerrs << "Failed to get thread local data" << llendl;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void initStorage();
|
||||
void destroyStorage();
|
||||
|
||||
protected:
|
||||
apr_threadkey_t* mThreadKey;
|
||||
static bool sInitialized;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class LLThreadLocalPointer : public LLThreadLocalPointerBase
|
||||
{
|
||||
public:
|
||||
|
||||
LLThreadLocalPointer()
|
||||
{}
|
||||
|
||||
explicit LLThreadLocalPointer(T* value)
|
||||
{
|
||||
set(value);
|
||||
}
|
||||
|
||||
|
||||
LLThreadLocalPointer(const LLThreadLocalPointer<T>& other)
|
||||
: LLThreadLocalPointerBase(other)
|
||||
{
|
||||
set(other.get());
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE T* get()
|
||||
{
|
||||
return (T*)LLThreadLocalPointerBase::get();
|
||||
}
|
||||
|
||||
const T* get() const
|
||||
{
|
||||
return (const T*)LLThreadLocalPointerBase::get();
|
||||
}
|
||||
|
||||
T* operator -> ()
|
||||
{
|
||||
return (T*)get();
|
||||
}
|
||||
|
||||
const T* operator -> () const
|
||||
{
|
||||
return (T*)get();
|
||||
}
|
||||
|
||||
T& operator*()
|
||||
{
|
||||
return *(T*)get();
|
||||
}
|
||||
|
||||
const T& operator*() const
|
||||
{
|
||||
return *(T*)get();
|
||||
}
|
||||
|
||||
LLThreadLocalPointer<T>& operator = (T* value)
|
||||
{
|
||||
set((void*)value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator ==(T* other)
|
||||
{
|
||||
if (!sInitialized) return false;
|
||||
return get() == other;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LL_LLTHREADLOCALPOINTER_H
|
||||
|
|
@ -34,6 +34,7 @@
|
|||
#include "llrefcount.h"
|
||||
#include "llunit.h"
|
||||
#include "llapr.h"
|
||||
#include "llthreadlocalpointer.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,11 @@
|
|||
#ifndef LL_LLWORKERTHREAD_H
|
||||
#define LL_LLWORKERTHREAD_H
|
||||
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "llqueuedthread.h"
|
||||
#include "llapr.h"
|
||||
|
|
|
|||
|
|
@ -28,6 +28,18 @@
|
|||
|
||||
#include "linden_common.h"
|
||||
|
||||
#if defined(LL_DARWIN)
|
||||
#include <QuickTime/QuickTime.h>
|
||||
#elif defined(LL_WINDOWS)
|
||||
#include "llwin32headers.h"
|
||||
#include "MacTypes.h"
|
||||
#include "QTML.h"
|
||||
#include "Movies.h"
|
||||
#include "QDoffscreen.h"
|
||||
#include "FixMath.h"
|
||||
#include "QTLoadLibraryUtils.h"
|
||||
#endif
|
||||
|
||||
#include "llgl.h"
|
||||
|
||||
#include "llplugininstance.h"
|
||||
|
|
@ -37,16 +49,7 @@
|
|||
|
||||
#if LL_QUICKTIME_ENABLED
|
||||
|
||||
#if defined(LL_DARWIN)
|
||||
#include <QuickTime/QuickTime.h>
|
||||
#elif defined(LL_WINDOWS)
|
||||
#include "MacTypes.h"
|
||||
#include "QTML.h"
|
||||
#include "Movies.h"
|
||||
#include "QDoffscreen.h"
|
||||
#include "FixMath.h"
|
||||
#include "QTLoadLibraryUtils.h"
|
||||
#endif
|
||||
|
||||
|
||||
// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
Loading…
Reference in New Issue