SH-3468 WIP add memory tracking base class

fixed crash on exit by making LLInstanceTracker iterators use atomic iterator
nesting count for thread safety
master
Richard Linden 2012-12-23 12:27:25 -08:00
parent 013f04cabe
commit 3fd640a6e3
9 changed files with 222 additions and 155 deletions

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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));
}

View File

@ -31,6 +31,7 @@
#include <algorithm>
#include <map>
#include <vector>
#include <list>
#include <set>
#include <deque>
#include <typeinfo>

View File

@ -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

View File

@ -34,6 +34,7 @@
#include "llrefcount.h"
#include "llunit.h"
#include "llapr.h"
#include "llthreadlocalpointer.h"
#include <list>

View File

@ -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"

View File

@ -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
////////////////////////////////////////////////////////////////////////////////