Merge remote-tracking branch 'aleric/V2MultiWear' into AltCompilers

This commit is contained in:
Drake Arconis
2012-07-02 21:08:04 +00:00
29 changed files with 523 additions and 1812 deletions

View File

@@ -168,19 +168,13 @@ long vfs_tell (void *datasource)
return file->tell();
}
LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const std::string &out_filename)
{
mDone = FALSE;
mValid = FALSE;
mBytesRead = -1;
mUUID = uuid;
mInFilep = NULL;
mCurrentSection = 0;
LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const std::string &out_filename) :
mValid(FALSE), mDone(FALSE), mBytesRead(-1), mUUID(uuid),
#if !defined(USE_WAV_VFILE)
mOutFilename = out_filename;
mFileHandle = LLLFSThread::nullHandle();
mOutFilename(out_filename), mFileHandle(LLLFSThread::nullHandle()),
#endif
// No default value for mVF, it's an ogg structure?
mInFilep(NULL), mCurrentSection(0)
{
}
LLVorbisDecodeState::~LLVorbisDecodeState()

View File

@@ -121,6 +121,7 @@ set(llcommon_HEADER_FILES
llaprpool.h
llassettype.h
llassoclist.h
llatomic.h
llavatarconstants.h
llbase32.h
llbase64.h

View File

@@ -26,8 +26,65 @@
*
* 31/03/2010
* Initial version, written by Aleric Inglewood @ SL
*
* 14/03/2012
* Added AIThreadSafeSingleThread and friends.
* Added AIAccessConst (and derived AIAccess from it) to allow read
* access to a const AIThreadSafeSimple.
*/
// This file defines wrapper template classes for arbitrary types T
// adding locking to the instance and shielding it from access
// without first being locked.
//
// Locking and getting access works by creating a temporary (local)
// access object that takes the wrapper class as argument. Creating
// the access object obtains the lock, while destructing it releases
// the lock.
//
// There are three types of wrapper classes:
// AIThreadSafe, AIThreadSafeSimple and AIThreadSafeSingleThread.
//
// AIThreadSafe is for use with the access classes:
// AIReadAccessConst, AIReadAccess and AIWriteAccess.
//
// AIThreadSafeSimple is for use with the access classes:
// AIAccessConst and AIAccess.
//
// AIThreadSafeSingleThread is for use with the access classes:
// AISTAccessConst and AISTAccess.
//
// AIReadAccessConst provides read access to a const AIThreadSafe.
// AIReadAccess provides read access to a non-const AIThreadSafe.
// AIWriteAccess provides read/write access to a non-const AIThreadSafe.
//
// AIAccessConst provides read access to a const AIThreadSafeSimple.
// AIAccess provides read/write access to a non-const AIThreadSafeSimple.
//
// AISTAccessConst provides read access to a const AIThreadSafeSingleThread.
// AISTAccess provides read/write access to a non-const AIThreadSafeSingleThread.
//
// Thus, AIThreadSafe is to protect objects with a read/write lock,
// AIThreadSafeSimple is to protect objects with a single mutex,
// and AIThreadSafeSingleThread doesn't do any locking but makes sure
// (in Debug mode) that the wrapped object is only accessed by one thread.
//
// Each wrapper class allows it's wrapped object to be constructed
// with arbitrary parameters by using operator new with placement;
// for example, to instantiate a class Foo with read/write locking:
//
// AIThreadSafe<Foo> foo(new (foo.memory()) Foo(param1, param2, ...));
//
// Each wrapper class has a derived class that end on 'DC' (which
// stand for Default Constructed): AIThreadSafeDC, AIThreadSafeSimpleDC
// and AIThreadSafeSingleThreadDC. The default constructors of those
// wrapper classes cause the wrapped instance to be default constructed
// as well. They also provide a general one-parameter constructor.
// For example:
//
// AIThreadSafeDC<Foo> foo; // Default constructed Foo.
// AIThreadSafeDC<Foo> foo(3.4); // Foo with one constructor parameter.
//
#ifndef AITHREADSAFE_H
#define AITHREADSAFE_H
@@ -49,15 +106,10 @@
template<typename T> struct AIReadAccessConst;
template<typename T> struct AIReadAccess;
template<typename T> struct AIWriteAccess;
template<typename T> struct AIAccessConst;
template<typename T> struct AIAccess;
#if LL_WINDOWS
template<typename T> class AIThreadSafeBits;
template<typename T>
struct AIThreadSafeWindowsHack {
AIThreadSafeWindowsHack(AIThreadSafeBits<T>& var, T* object);
};
#endif
template<typename T> struct AISTAccessConst;
template<typename T> struct AISTAccess;
template<typename T>
class AIThreadSafeBits
@@ -80,10 +132,15 @@ public:
// Only for use by AITHREADSAFE, see below.
void* memory() const { return const_cast<long*>(&mMemory[0]); }
// Cast a T* back to AIThreadSafeBits<T>. This is the inverse of memory().
template<typename T2>
static AIThreadSafeBits<T2>* wrapper_cast(T2* ptr)
{ return reinterpret_cast<AIThreadSafeBits<T2>*>(reinterpret_cast<char*>(ptr) - offsetof(AIThreadSafeBits<T2>, mMemory[0])); }
template<typename T2>
static AIThreadSafeBits<T2> const* wrapper_cast(T2 const* ptr)
{ return reinterpret_cast<AIThreadSafeBits<T2> const*>(reinterpret_cast<char const*>(ptr) - offsetof(AIThreadSafeBits<T2>, mMemory[0])); }
protected:
#if LL_WINDOWS
template<typename T2> friend struct AIThreadSafeWindowsHack;
#endif
// Accessors.
T const* ptr() const { return reinterpret_cast<T const*>(mMemory); }
T* ptr() { return reinterpret_cast<T*>(mMemory); }
@@ -185,6 +242,14 @@ public:
llassert(object == AIThreadSafeBits<T>::ptr());
#endif
}
#if LL_DEBUG
// Can only be locked when there still exists an AIAccess object that
// references this object and will access it upon destruction.
// If the assertion fails, make sure that such AIAccess object is
// destructed before the deletion of this object.
~AIThreadSafe() { llassert(!mRWLock.isLocked()); }
#endif
};
/**
@@ -194,48 +259,39 @@ public:
*
* <code>
* Foo foo(x, y);
* static Bar bar;
* static Bar bar(0.1, true);
* </code>
*
* One can instantiate a thread-safe instance with
*
* <code>
* AITHREADSAFE(Foo, foo, (x, y));
* static AITHREADSAFE(Bar, bar, );
* static AITHREADSAFE(Bar, bar, (0.1, true));
* </code>
*
* Note: This macro does not allow to allocate such object on the heap.
* If that is needed, have a look at AIThreadSafeDC.
*/
#if LL_WINDOWS
template<typename T>
AIThreadSafeWindowsHack<T>::AIThreadSafeWindowsHack(AIThreadSafeBits<T>& var, T* object)
{
llassert(object == var.ptr());
}
#define AITHREADSAFE(type, var, paramlist) \
AIThreadSafe<type> var(NULL); \
AIThreadSafeWindowsHack<type> dummy_##var(var, new (var.memory()) type paramlist)
#else
#define AITHREADSAFE(type, var, paramlist) AIThreadSafe<type> var(new (var.memory()) type paramlist)
#endif
/**
* @brief A wrapper class for objects that need to be accessed by more than one thread.
*
* This class is the same as an AIThreadSafe wrapper, except that it can only
* be used for default constructed objects.
* be used for default constructed objects, or constructed with one parameter.
*
* For example, instead of
*
* <code>
* Foo foo;
* Bar bar(3);
* </code>
*
* One would use
*
* <code>
* AIThreadSafeDC<Foo> foo;
* AIThreadSafeDC<Bar> bar(3);
* </code>
*
* The advantage over AITHREADSAFE is that this object can be allocated with
@@ -253,6 +309,8 @@ class AIThreadSafeDC : public AIThreadSafe<T>
public:
// Construct a wrapper around a default constructed object.
AIThreadSafeDC(void) { new (AIThreadSafe<T>::ptr()) T; }
// Allow an arbitrary parameter to be passed for construction.
template<typename T2> AIThreadSafeDC(T2 const& val) { new (AIThreadSafe<T>::ptr()) T(val); }
};
/**
@@ -390,6 +448,7 @@ struct AIWriteAccess : public AIReadAccess<T>
*
* AIAccess<Foo> foo_w(foo);
* // Use foo_w-> for read and write access.
* </code>
*
* See also AIThreadSafe
*/
@@ -398,6 +457,7 @@ class AIThreadSafeSimple : public AIThreadSafeBits<T>
{
protected:
// Only this one may access the object (through ptr()).
friend struct AIAccessConst<T>;
friend struct AIAccess<T>;
// Locking control.
@@ -411,6 +471,14 @@ protected:
public:
// Only for use by AITHREADSAFESIMPLE, see below.
AIThreadSafeSimple(T* object) { llassert(object == AIThreadSafeBits<T>::ptr()); }
#if LL_DEBUG
// Can only be locked when there still exists an AIAccess object that
// references this object and will access it upon destruction.
// If the assertion fails, make sure that such AIAccess object is
// destructed before the deletion of this object.
~AIThreadSafeSimple() { llassert(!mMutex.isLocked()); }
#endif
};
/**
@@ -420,14 +488,14 @@ public:
*
* <code>
* Foo foo(x, y);
* static Bar bar;
* static Bar bar(0.1, true);
* </code>
*
* One can instantiate a thread-safe instance with
*
* <code>
* AITHREADSAFESIMPLE(Foo, foo, (x, y));
* static AITHREADSAFESIMPLE(Bar, bar, );
* static AITHREADSAFESIMPLE(Bar, bar, (0.1, true));
* </code>
*
* Note: This macro does not allow to allocate such object on the heap.
@@ -439,18 +507,20 @@ public:
* @brief A wrapper class for objects that need to be accessed by more than one thread.
*
* This class is the same as an AIThreadSafeSimple wrapper, except that it can only
* be used for default constructed objects.
* be used for default constructed objects, or constructed with one parameter.
*
* For example, instead of
*
* <code>
* Foo foo;
* Bar bar(0.1);
* </code>
*
* One would use
*
* <code>
* AIThreadSafeSimpleDC<Foo> foo;
* AIThreadSafeSimpleDC<Bar> bar(0.1);
* </code>
*
* The advantage over AITHREADSAFESIMPLE is that this object can be allocated with
@@ -468,10 +538,12 @@ class AIThreadSafeSimpleDC : public AIThreadSafeSimple<T>
public:
// Construct a wrapper around a default constructed object.
AIThreadSafeSimpleDC(void) { new (AIThreadSafeSimple<T>::ptr()) T; }
// Allow an arbitrary parameter to be passed for construction.
template<typename T2> AIThreadSafeSimpleDC(T2 const& val) { new (AIThreadSafeSimple<T>::ptr()) T(val); }
protected:
// For use by AIThreadSafeSimpleDCRootPool
AIThreadSafeSimpleDC(LLAPRPool& parent) : AIThreadSafeSimple<T>(parent) { new (AIThreadSafeSimple<T>::ptr()) T; }
AIThreadSafeSimpleDC(LLAPRRootPool& parent) : AIThreadSafeSimple<T>(parent) { new (AIThreadSafeSimple<T>::ptr()) T; }
};
// Helper class for AIThreadSafeSimpleDCRootPool to assure initialization of
@@ -509,13 +581,13 @@ public:
};
/**
* @brief Write lock object and provide read/write access.
* @brief Write lock object and provide read access.
*/
template<typename T>
struct AIAccess
struct AIAccessConst
{
//! Construct a AIAccess from a non-constant AIThreadSafeSimple.
AIAccess(AIThreadSafeSimple<T>& wrapper) : mWrapper(wrapper)
//! Construct a AIAccessConst from a constant AIThreadSafeSimple.
AIAccessConst(AIThreadSafeSimple<T> const& wrapper) : mWrapper(const_cast<AIThreadSafeSimple<T>&>(wrapper))
#if AI_NEED_ACCESS_CC
, mIsCopyConstructed(false)
#endif
@@ -524,12 +596,12 @@ struct AIAccess
}
//! Access the underlaying object for (read and) write access.
T* operator->() const { return this->mWrapper.ptr(); }
T const* operator->() const { return this->mWrapper.ptr(); }
//! Access the underlaying object for (read and) write access.
T& operator*() const { return *this->mWrapper.ptr(); }
T const& operator*() const { return *this->mWrapper.ptr(); }
~AIAccess()
~AIAccessConst()
{
#if AI_NEED_ACCESS_CC
if (mIsCopyConstructed) return;
@@ -538,17 +610,229 @@ struct AIAccess
}
protected:
AIThreadSafeSimple<T>& mWrapper; //!< Reference to the object that we provide access to.
AIThreadSafeSimple<T>& mWrapper; //!< Reference to the object that we provide access to.
#if AI_NEED_ACCESS_CC
bool mIsCopyConstructed;
public:
AIAccess(AIAccess const& orig) : mWrapper(orig.mWrapper), mIsCopyConstructed(true) { }
AIAccessConst(AIAccessConst const& orig) : mWrapper(orig.mWrapper), mIsCopyConstructed(true) { }
#else
private:
// Disallow copy constructing directly.
AIAccess(AIAccess const&);
AIAccessConst(AIAccessConst const&);
#endif
};
/**
* @brief Write lock object and provide read/write access.
*/
template<typename T>
struct AIAccess : public AIAccessConst<T>
{
//! Construct a AIAccess from a non-constant AIThreadSafeSimple.
AIAccess(AIThreadSafeSimple<T>& wrapper) : AIAccessConst<T>(wrapper) { }
//! Access the underlaying object for (read and) write access.
T* operator->() const { return this->mWrapper.ptr(); }
//! Access the underlaying object for (read and) write access.
T& operator*() const { return *this->mWrapper.ptr(); }
};
/**
* @brief A wrapper class for objects that should only be accessed by a single thread.
*
* Use AITHREADSAFESINGLETHREAD to define instances of any type, and use AISTAccess
* to get access to the instance.
*
* For example,
*
* <code>
* class Foo { public: Foo(int, int); };
*
* AITHREADSAFESINGLETHREAD(Foo, foo, (2, 3));
*
* AISTAccess<Foo> foo_w(foo);
* // Use foo_w-> for read and write access.
* </code>
*/
template<typename T>
class AIThreadSafeSingleThread : public AIThreadSafeBits<T>
{
protected:
// Only these one may access the object (through ptr()).
friend struct AISTAccessConst<T>;
friend struct AISTAccess<T>;
// For use by AIThreadSafeSingleThreadDC.
AIThreadSafeSingleThread(void)
#ifdef LL_DEBUG
: mAccessed(false)
#endif
{ }
#ifdef LL_DEBUG
mutable bool mAccessed;
mutable apr_os_thread_t mTheadID;
void accessed(void) const
{
if (!mAccessed)
{
mAccessed = true;
mTheadID = apr_os_thread_current();
}
else
{
llassert_always(apr_os_thread_equal(mTheadID, apr_os_thread_current()));
}
}
#endif
public:
// Only for use by AITHREADSAFESINGLETHREAD, see below.
AIThreadSafeSingleThread(T* object)
#ifdef LL_DEBUG
: mAccessed(false)
#endif
{
llassert(object == AIThreadSafeBits<T>::ptr());
}
private:
// Disallow copying or assignments.
AIThreadSafeSingleThread(AIThreadSafeSingleThread const&);
void operator=(AIThreadSafeSingleThread const&);
};
/**
* @brief A wrapper class for objects that should only be accessed by a single thread.
*
* This class is the same as an AIThreadSafeSingleThread wrapper, except that it can only
* be used for default constructed objects, or constructed with one parameter.
*
* For example, instead of
*
* <code>
* Foo foo;
* Bar bar(0.1);
* </code>
*
* One would use
*
* <code>
* AIThreadSafeSingleThreadDC<Foo> foo;
* AIThreadSafeSingleThreadDC<Bar> bar(0.1);
* </code>
*
* The advantage over AITHREADSAFESINGLETHREAD is that this object can be allocated with
* new on the heap. For example:
*
* <code>
* AIThreadSafeSingleThreadDC<Foo>* ptr = new AIThreadSafeSingleThreadDC<Foo>;
* </code>
*
* which is not possible with AITHREADSAFESINGLETHREAD.
*
* This class is primarily intended to test if some (member) variable needs locking,
* during development (in debug mode), and is therefore more flexible in that it
* automatically converts to the underlaying type, can be assigned to and can be
* written to an ostream, as if it wasn't wrapped at all. This is to reduce the
* impact on the source code.
*/
template<typename T>
class AIThreadSafeSingleThreadDC : public AIThreadSafeSingleThread<T>
{
public:
// Construct a wrapper around a default constructed object.
AIThreadSafeSingleThreadDC(void) { new (AIThreadSafeSingleThread<T>::ptr()) T; }
// Allow an arbitrary parameter to be passed for construction.
template<typename T2> AIThreadSafeSingleThreadDC(T2 const& val) { new (AIThreadSafeSingleThread<T>::ptr()) T(val); }
// Allow assigning with T.
AIThreadSafeSingleThreadDC& operator=(T const& val) { AIThreadSafeSingleThread<T>::accessed(); *AIThreadSafeSingleThread<T>::ptr() = val; return *this; }
// Allow writing to an ostream.
friend std::ostream& operator<<(std::ostream& os, AIThreadSafeSingleThreadDC const& wrapped_val) { wrapped_val.accessed(); return os << *wrapped_val.ptr(); }
// Automatic conversion to T.
operator T&(void) { AIThreadSafeSingleThread<T>::accessed(); return *AIThreadSafeSingleThread<T>::ptr(); }
operator T const&(void) const { AIThreadSafeSingleThread<T>::accessed(); return *AIThreadSafeSingleThread<T>::ptr(); }
};
/**
* @brief Instantiate a static, global or local object of a given type wrapped in AIThreadSafeSingleThread, using an arbitrary constructor.
*
* For example, instead of doing
*
* <code>
* Foo foo(x, y);
* static Bar bar;
* </code>
*
* One can instantiate a thread-safe instance with
*
* <code>
* AITHREADSAFESINGLETHREAD(Foo, foo, (x, y));
* static AITHREADSAFESINGLETHREAD(Bar, bar, );
* </code>
*
* Note: This macro does not allow to allocate such object on the heap.
* If that is needed, have a look at AIThreadSafeSingleThreadDC.
*/
#define AITHREADSAFESINGLETHREAD(type, var, paramlist) AIThreadSafeSingleThread<type> var(new (var.memory()) type paramlist)
/**
* @brief Access single threaded object for read access.
*/
template<typename T>
struct AISTAccessConst
{
//! Construct a AISTAccessConst from a constant AIThreadSafeSingleThread.
AISTAccessConst(AIThreadSafeSingleThread<T> const& wrapper) : mWrapper(const_cast<AIThreadSafeSingleThread<T>&>(wrapper))
{
#if LL_DEBUG
wrapper.accessed();
#endif
}
//! Access the underlaying object for read access.
T const* operator->() const { return this->mWrapper.ptr(); }
//! Access the underlaying object for read write access.
T const& operator*() const { return *this->mWrapper.ptr(); }
protected:
AIThreadSafeSingleThread<T>& mWrapper; //!< Reference to the object that we provide access to.
#if AI_NEED_ACCESS_CC
public:
AISTAccessConst(AISTAccessConst const& orig) : mWrapper(orig.mWrapper) { }
#else
private:
// Disallow copy constructing directly.
AISTAccessConst(AISTAccessConst const&);
#endif
};
/**
* @brief Access single threaded object for read/write access.
*/
template<typename T>
struct AISTAccess : public AISTAccessConst<T>
{
//! Construct a AISTAccess from a non-constant AIThreadSafeSingleThread.
AISTAccess(AIThreadSafeSingleThread<T>& wrapper) : AISTAccessConst<T>(wrapper)
{
#if LL_DEBUG
wrapper.accessed();
#endif
}
//! Access the underlaying object for (read and) write access.
T* operator->() const { return this->mWrapper.ptr(); }
//! Access the underlaying object for (read and) write access.
T& operator*() const { return *this->mWrapper.ptr(); }
};
#endif

View File

@@ -88,7 +88,7 @@ bool ll_apr_warn_status(apr_status_t status)
void ll_apr_assert_status(apr_status_t status)
{
llassert(ll_apr_warn_status(status) == false);
llassert(!ll_apr_warn_status(status));
}
//---------------------------------------------------------------------
@@ -146,7 +146,7 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
apr_status_t status;
{
apr_pool_t* apr_file_open_pool;
apr_pool_t* apr_file_open_pool; // The use of apr_pool_t is OK here.
// This is a temporary variable for a pool that is passed directly to apr_file_open below.
if (access_type == short_lived)
{
@@ -199,7 +199,6 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOO
// File I/O
S32 LLAPRFile::read(void *buf, S32 nbytes)
{
//llassert_always(mFile); (ASC-TUDCC) -HgB
if(!mFile)
{
llwarns << "apr mFile is removed by somebody else. Can not read." << llendl ;
@@ -222,7 +221,6 @@ S32 LLAPRFile::read(void *buf, S32 nbytes)
S32 LLAPRFile::write(const void *buf, S32 nbytes)
{
// llassert_always(mFile); (ASC-TUDCC) -HgB
if(!mFile)
{
llwarns << "apr mFile is removed by somebody else. Can not write." << llendl ;

View File

@@ -91,29 +91,8 @@ protected:
apr_thread_mutex_t* mMutex;
};
template <typename Type> class LLAtomic32
{
public:
LLAtomic32<Type>() {};
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); }
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); } // Type--
private:
apr_uint32_t mData;
};
typedef LLAtomic32<U32> LLAtomicU32;
typedef LLAtomic32<S32> LLAtomicS32;
// File IO convenience functions.
// Returns NULL if the file fails to openm sets *sizep to file size of not NULL
// Returns NULL if the file fails to open, sets *sizep to file size if not NULL
// abbreviated flags
#define LL_APR_R (APR_READ) // "r"
#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w"
@@ -131,7 +110,7 @@ typedef LLAtomic32<S32> LLAtomicS32;
// especially do not put some time-costly operations between open() and close().
// otherwise it might lock the APRFilePool.
//there are two different apr_pools the APRFile can use:
// 1, a temperary pool passed to an APRFile function, which is used within this function and only once.
// 1, a temporary pool passed to an APRFile function, which is used within this function and only once.
// 2, a global pool.
//
@@ -189,7 +168,7 @@ public:
};
/**
* @brief Function which approprately logs error or remains quiet on
* @brief Function which appropriately logs error or remains quiet on
* APR_SUCCESS.
* @return Returns <code>true</code> if status is an error condition.
*/

View File

@@ -1,5 +1,5 @@
/**
* @file LLAPRPool.cpp
* @file llaprpool.cpp
*
* Copyright (c) 2010, Aleric Inglewood.
*

View File

@@ -1,5 +1,5 @@
/**
* @file LLAPRPool.h
* @file llaprpool.h
* @brief Implementation of LLAPRPool.
*
* Copyright (c) 2010, Aleric Inglewood.
@@ -60,9 +60,9 @@ extern void ll_init_apr();
class LL_COMMON_API LLAPRPool
{
protected:
apr_pool_t* mPool; //!< Pointer to the underlaying pool. NULL if not initialized.
apr_pool_t* mPool; //!< Pointer to the underlaying pool. NULL if not initialized.
LLAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero.
apr_os_thread_t mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero.
apr_os_thread_t mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero.
public:
//! Construct an uninitialized (destructed) pool.

61
indra/llcommon/llatomic.h Normal file
View File

@@ -0,0 +1,61 @@
/**
* @file llatomic.h
* @brief Definition of LLAtomic
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
* Copyright (c) 2012, Aleric Inglewood
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLATOMIC_H
#define LL_LLATOMIC_H
#include "apr_atomic.h"
template <typename Type> class LLAtomic32
{
public:
LLAtomic32(void) { }
LLAtomic32(LLAtomic32 const& atom) { apr_uint32_t data = apr_atomic_read32(const_cast<apr_uint32_t*>(&atom.mData)); apr_atomic_set32(&mData, data); }
LLAtomic32(Type x) { apr_atomic_set32(&mData, static_cast<apr_uint32_t>(x)); }
LLAtomic32& operator=(LLAtomic32 const& atom) { apr_uint32_t data = apr_atomic_read32(const_cast<apr_uint32_t*>(&atom.mData)); apr_atomic_set32(&mData, data); return *this; }
operator Type() const { apr_uint32_t data = apr_atomic_read32(const_cast<apr_uint32_t*>(&mData)); return static_cast<Type>(data); }
void operator=(Type x) { apr_atomic_set32(&mData, static_cast<apr_uint32_t>(x)); }
void operator-=(Type x) { apr_atomic_sub32(&mData, static_cast<apr_uint32_t>(x)); }
void operator+=(Type x) { apr_atomic_add32(&mData, static_cast<apr_uint32_t>(x)); }
Type operator++(int) { return apr_atomic_inc32(&mData); } // Type++
bool operator--() { return apr_atomic_dec32(&mData); } // Returns (--Type != 0)
private:
apr_uint32_t mData;
};
typedef LLAtomic32<U32> LLAtomicU32;
typedef LLAtomic32<S32> LLAtomicS32;
#endif

View File

@@ -39,7 +39,6 @@ void LLCommon::initClass()
{
LLMemory::initClass();
LLTimer::initClass();
LLThreadSafeRefCount::initThreadSafeRefCount();
// LLWorkerThread::initClass();
// LLFrameCallbackManager::initClass();
}
@@ -49,7 +48,6 @@ void LLCommon::cleanupClass()
{
// LLFrameCallbackManager::cleanupClass();
// LLWorkerThread::cleanupClass();
LLThreadSafeRefCount::cleanupThreadSafeRefCount();
LLTimer::cleanupClass();
LLMemory::cleanupClass();
}

View File

@@ -39,7 +39,7 @@ class LLSD;
class LLOptionInterface
{
public:
virtual ~LLOptionInterface() = 0;
virtual ~LLOptionInterface();
virtual LLSD getOption(const std::string& name) const = 0;
};

View File

@@ -44,7 +44,7 @@
#include "llsimplehash.h"
//============================================================================
// Note: ~LLQueuedThread is O(N) N=# of queued threads, assumed to be small
// Note: ~LLQueuedThread is O(N) N=# of queued requests, assumed to be small
// It is assumed that LLQueuedThreads are rarely created/destroyed.
class LL_COMMON_API LLQueuedThread : public LLThread

View File

@@ -104,6 +104,11 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
// the moment it happens... therefore make a copy here.
char const* volatile name = threadp->mName.c_str();
// Always make sure that sRunning <= number of threads with status RUNNING,
// so do this before changing mStatus (meaning that once we see that we
// are STOPPED, then sRunning is also up to date).
--sRunning;
// We're done with the run function, this thread is done executing now.
threadp->mStatus = STOPPED;
@@ -178,7 +183,7 @@ void LLThread::shutdown()
}
mAPRThreadp = NULL;
}
sCount--;
--sCount;
delete mRunCondition;
mRunCondition = 0;
}
@@ -402,6 +407,15 @@ LLMutexBase::LLMutexBase() :
{
}
bool LLMutexBase::isSelfLocked() const
{
#if LL_DARWIN
return mLockingThread == LLThread::currentID();
#else
return mLockingThread == local_thread_ID;
#endif
}
void LLMutexBase::lock()
{
#if LL_DARWIN
@@ -435,37 +449,6 @@ void LLMutexBase::unlock()
apr_thread_mutex_unlock(mAPRMutexp);
}
bool LLMutexBase::isSelfLocked()
{
#if LL_DARWIN
return mLockingThread == LLThread::currentID();
#else
return mLockingThread == local_thread_ID;
#endif
}
//----------------------------------------------------------------------------
//static
LLMutex* LLThreadSafeRefCount::sMutex = 0;
//static
void LLThreadSafeRefCount::initThreadSafeRefCount()
{
if (!sMutex)
{
sMutex = new LLMutex;
}
}
//static
void LLThreadSafeRefCount::cleanupThreadSafeRefCount()
{
delete sMutex;
sMutex = NULL;
}
//----------------------------------------------------------------------------
LLThreadSafeRefCount::LLThreadSafeRefCount() :

View File

@@ -38,9 +38,13 @@
#include "llmemory.h"
#include "apr_thread_cond.h"
#include "llaprpool.h"
#include "llatomic.h"
#ifdef SHOW_ASSERT
extern LL_COMMON_API bool is_main_thread(void);
#define ASSERT_SINGLE_THREAD do { static apr_os_thread_t first_thread_id = apr_os_thread_current(); llassert(apr_os_thread_equal(first_thread_id, apr_os_thread_current())); } while(0)
#else
#define ASSERT_SINGLE_THREAD do { } while(0)
#endif
class LLThread;
@@ -74,7 +78,7 @@ class LL_COMMON_API LLThread
private:
static U32 sIDIter;
static LLAtomicS32 sCount;
public:
typedef enum e_thread_status
{
@@ -181,15 +185,18 @@ public:
LLMutexBase() ;
void lock(); //blocks
void lock(); // blocks
void unlock();
// Returns true if lock was obtained successfully.
bool tryLock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); }
// non-blocking, but does do a lock/unlock so not free
bool isLocked() { bool is_not_locked = tryLock(); if (is_not_locked) unlock(); return !is_not_locked; }
// Returns true if locked by this thread.
bool isSelfLocked() const;
// get ID of locking thread
bool isSelfLocked(); //return true if locked in a same thread
U32 lockingThread() const { return mLockingThread; }
protected:
@@ -394,13 +401,6 @@ void LLThread::unlockData()
class LL_COMMON_API LLThreadSafeRefCount
{
public:
static void initThreadSafeRefCount(); // creates sMutex
static void cleanupThreadSafeRefCount(); // destroys sMutex
private:
static LLMutex* sMutex;
private:
LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented
LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented
@@ -413,31 +413,20 @@ public:
void ref()
{
if (sMutex) sMutex->lock();
mRef++;
if (sMutex) sMutex->unlock();
}
S32 unref()
void unref()
{
llassert(mRef >= 1);
if (sMutex) sMutex->lock();
S32 res = --mRef;
if (sMutex) sMutex->unlock();
if (0 == res)
{
delete this;
return 0;
}
return res;
}
if (!--mRef) delete this;
}
S32 getNumRefs() const
{
return mRef;
}
private:
S32 mRef;
LLAtomicS32 mRef;
};
//============================================================================

View File

@@ -269,7 +269,7 @@ U8* LLImageBase::allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 si
// LLImageRaw
//---------------------------------------------------------------------------
AITHREADSAFESIMPLE(S32, LLImageRaw::sGlobalRawMemory, );
AIThreadSafeSimpleDC<S32> LLImageRaw::sGlobalRawMemory;
S32 LLImageRaw::sRawImageCount = 0;
S32 LLImageRaw::sRawImageCachedCount = 0;

View File

@@ -248,7 +248,7 @@ protected:
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
public:
static AIThreadSafeSimple<S32> sGlobalRawMemory;
static AIThreadSafeSimpleDC<S32> sGlobalRawMemory;
static S32 sRawImageCount;
static S32 sRawImageCachedCount;

View File

@@ -34,7 +34,6 @@ set(llmessage_SOURCE_FILES
lldispatcher.cpp
llfiltersd2xmlrpc.cpp
llhost.cpp
llhttpassetstorage.cpp
llhttpclient.cpp
llhttpclientadapter.cpp
llhttpnode.cpp
@@ -125,7 +124,6 @@ set(llmessage_HEADER_FILES
llfiltersd2xmlrpc.h
llfollowcamparams.h
llhost.h
llhttpassetstorage.h
llhttpclient.h
llhttpclientinterface.h
llhttpclientadapter.h

File diff suppressed because it is too large Load Diff

View File

@@ -1,159 +0,0 @@
/**
* @file llhttpassetstorage.h
* @brief Class for loading asset data to/from an external source over http.
*
* $LicenseInfo:firstyear=2003&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 LLHTTPASSETSTORAGE_H
#define LLHTTPASSETSTORAGE_H
#include "llassetstorage.h"
#include "curl/curl.h"
class LLVFile;
class LLHTTPAssetRequest;
typedef void (*progress_callback)(void* userdata);
struct LLTempAssetData;
typedef std::map<LLUUID,LLTempAssetData> uuid_tempdata_map;
class LLHTTPAssetStorage : public LLAssetStorage
{
public:
LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
LLVFS *vfs, LLVFS *static_vfs,
const LLHost &upstream_host,
const std::string& web_host,
const std::string& local_web_host,
const std::string& host_name);
LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
LLVFS *vfs, LLVFS *static_vfs,
const std::string& web_host,
const std::string& local_web_host,
const std::string& host_name);
virtual ~LLHTTPAssetStorage();
using LLAssetStorage::storeAssetData; // Unhiding virtuals...
virtual void storeAssetData(
const LLUUID& uuid,
LLAssetType::EType atype,
LLStoreAssetCallback callback,
void* user_data,
bool temp_file = false,
bool is_priority = false,
bool store_local = false,
const LLUUID& requesting_agent_id = LLUUID::null,
bool user_waiting=FALSE,
F64 timeout=LL_ASSET_STORAGE_TIMEOUT);
virtual void storeAssetData(
const std::string& filename,
const LLUUID& asset_id,
LLAssetType::EType atype,
LLStoreAssetCallback callback,
void* user_data,
bool temp_file,
bool is_priority,
bool user_waiting=FALSE,
F64 timeout=LL_ASSET_STORAGE_TIMEOUT);
virtual LLSD getPendingDetails(ERequestType rt,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const;
virtual LLSD getPendingRequest(ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id) const;
virtual bool deletePendingRequest(ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
// Hack. One off curl download an URL to a file. Probably should be elsewhere.
// Only used by lldynamicstate. The API is broken, and should be replaced with
// a generic HTTP file fetch - Doug 9/25/06
S32 getURLToFile(const LLUUID& uuid, LLAssetType::EType asset_type, const std::string &url, const std::string& filename, progress_callback callback, void *userdata);
LLAssetRequest* findNextRequest(request_list_t& pending, request_list_t& running);
void checkForTimeouts();
static size_t curlDownCallback(void *data, size_t size, size_t nmemb, void *user_data);
static size_t curlFileDownCallback(void *data, size_t size, size_t nmemb, void *user_data);
static size_t curlUpCallback(void *data, size_t size, size_t nmemb, void *user_data);
static size_t nullOutputCallback(void *data, size_t size, size_t nmemb, void *user_data);
// Should only be used by the LLHTTPAssetRequest
void addRunningRequest(ERequestType rt, LLHTTPAssetRequest* request);
void removeRunningRequest(ERequestType rt, LLHTTPAssetRequest* request);
request_list_t* getRunningList(ERequestType rt);
const request_list_t* getRunningList(ERequestType rt) const;
// Temp assets are stored on sim nodes, they have agent ID and location data associated with them.
virtual void addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name);
virtual BOOL hasTempAssetData(const LLUUID& texture_id) const;
virtual std::string getTempAssetHostName(const LLUUID& texture_id) const;
virtual LLUUID getTempAssetAgentID(const LLUUID& texture_id) const;
virtual void removeTempAssetData(const LLUUID& asset_id);
virtual void removeTempAssetDataByAgentID(const LLUUID& agent_id);
// Pass LLUUID::null for all
virtual void dumpTempAssetData(const LLUUID& avatar_id) const;
virtual void clearTempAssetData();
protected:
void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type,
void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
void *user_data, BOOL duplicate, BOOL is_priority);
private:
void _init(const std::string& web_host, const std::string& local_web_host, const std::string& host_name);
// This will return the correct base URI for any http asset request
std::string getBaseURL(const LLUUID& asset_id, LLAssetType::EType asset_type);
// Check for running uploads that have timed out
// Bump these to the back of the line to let other uploads complete.
void bumpTimedOutUploads();
protected:
std::string mBaseURL;
std::string mLocalBaseURL;
std::string mHostName;
CURLM *mCurlMultiHandle;
request_list_t mRunningDownloads;
request_list_t mRunningUploads;
request_list_t mRunningLocalUploads;
uuid_tempdata_map mTempAssets;
};
#endif

View File

@@ -99,7 +99,22 @@ int LLPluginInstance::load(std::string &plugin_file)
if(result != APR_SUCCESS)
{
char buf[1024];
apr_dso_error(mDSOHandle, buf, sizeof(buf));
#if LL_LINUX && defined(LL_STANDALONE)
if (!dso_handle)
{
char* error = dlerror();
buf[0] = 0;
if (error)
{
strncpy(buf, dlerror(), sizeof(buf));
}
buf[sizeof(buf) - 1] = 0;
}
else
#endif
{
apr_dso_error(mDSOHandle, buf, sizeof(buf));
}
#if LL_LINUX && defined(LL_STANDALONE)
LL_WARNS("Plugin") << "plugin load " << plugin_file << " failed with error " << result << " , additional info string: " << buf << LL_ENDL;

View File

@@ -191,7 +191,7 @@ int main(int argc, char **argv)
#ifdef CWDEBUG
Debug( libcw_do.margin().assign("SLPlugin ", 9) );
Debug(debug::init());
// Uncomment this to automatically open a terminal with gdb. Requires SNOW-173.
// Uncomment this to automatically open a terminal with gdb.
//Debug(attach_gdb());
#endif

View File

@@ -1400,13 +1400,13 @@ void LLVertexBuffer::setupVertexArray()
//glVertexattribIPointer requires GLSL 1.30 or later
if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30)
{
glVertexAttribIPointer(i, attrib_size[i], attrib_type[i], sTypeSize[i], (void*) mOffsets[i]);
glVertexAttribIPointer(i, attrib_size[i], attrib_type[i], sTypeSize[i], reinterpret_cast<void*>(mOffsets[i]));
}
#endif
}
else
{
glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]);
glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], reinterpret_cast<void*>(mOffsets[i]));
}
}
else

View File

@@ -38,6 +38,7 @@
#endif
#include "linden_common.h"
#include "llaprpool.h"
extern "C" {
#include <dbus/dbus-glib.h>
@@ -55,8 +56,8 @@ extern "C" {
#undef LL_DBUS_SYM
static bool sSymsGrabbed = false;
static apr_pool_t *sSymDBUSDSOMemoryPool = NULL;
static apr_dso_handle_t *sSymDBUSDSOHandleG = NULL;
static LLAPRPool sSymDBUSDSOMemoryPool; // Used for sSymDBUSDSOHandleG (and what it is pointing at?)
static apr_dso_handle_t* sSymDBUSDSOHandleG = NULL;
bool grab_dbus_syms(std::string dbus_dso_name)
{
@@ -74,18 +75,18 @@ bool grab_dbus_syms(std::string dbus_dso_name)
#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##DBUSSYM, sSymDBUSDSOHandle, #DBUSSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #DBUSSYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #DBUSSYM, (void*)ll##DBUSSYM);}while(0)
//attempt to load the shared library
apr_pool_create(&sSymDBUSDSOMemoryPool, NULL);
sSymDBUSDSOMemoryPool.create();
#ifdef LL_STANDALONE
void *dso_handle = dlopen(dbus_dso_name.c_str(), RTLD_NOW | RTLD_GLOBAL);
rv = (!dso_handle)?APR_EDSOOPEN:apr_os_dso_handle_put(&sSymDBUSDSOHandle,
dso_handle, sSymDBUSDSOMemoryPool);
dso_handle, sSymDBUSDSOMemoryPool());
if ( APR_SUCCESS == rv )
#else
if ( APR_SUCCESS == (rv = apr_dso_load(&sSymDBUSDSOHandle,
dbus_dso_name.c_str(),
sSymDBUSDSOMemoryPool) ))
sSymDBUSDSOMemoryPool()) ))
#endif
{
INFOMSG("Found DSO: %s", dbus_dso_name.c_str());
@@ -113,6 +114,10 @@ bool grab_dbus_syms(std::string dbus_dso_name)
#undef LL_DBUS_SYM
sSymsGrabbed = rtn;
if (!sSymsGrabbed)
{
sSymDBUSDSOMemoryPool.destroy();
}
return rtn;
}
@@ -127,13 +132,9 @@ void ungrab_dbus_syms()
apr_dso_unload(sSymDBUSDSOHandleG);
sSymDBUSDSOHandleG = NULL;
}
if ( sSymDBUSDSOMemoryPool )
{
apr_pool_destroy(sSymDBUSDSOMemoryPool);
sSymDBUSDSOMemoryPool = NULL;
}
sSymDBUSDSOMemoryPool.destroy();
// NULL-out all of the symbols we'd grabbed
#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{ll##DBUSSYM = NULL;}while(0)
#include "llappviewerlinux_api_dbus_syms_raw.inc"

View File

@@ -87,7 +87,7 @@
BOOL gHackGodmode = FALSE;
#endif
AITHREADSAFE(settings_map_type, gSettings,);
AIThreadSafeDC<settings_map_type> gSettings;
LLControlGroup gSavedSettings("Global"); // saved at end of session
LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session
LLControlGroup gColors("Colors"); // saved at end of session

View File

@@ -51,7 +51,7 @@ extern BOOL gHackGodmode;
void settings_setup_listeners();
typedef std::map<std::string, LLControlGroup*> settings_map_type;
extern AIThreadSafe<settings_map_type> gSettings;
extern AIThreadSafeDC<settings_map_type> gSettings;
// for the graphics settings
void create_graphics_group(LLControlGroup& group);

View File

@@ -64,22 +64,8 @@ inline void AIRegisteredStateMachines::trigger(void)
}
// A list (array) with all AIRegisteredStateMachines maps, one for each event type.
struct AIRegisteredStateMachinesList {
AIThreadSafeSimple<AIRegisteredStateMachines> mRegisteredStateMachinesList[AIEvent::number_of_events];
AIRegisteredStateMachinesList(void);
AIThreadSafeSimple<AIRegisteredStateMachines>& operator[](AIEvent::AIEvents event) { return mRegisteredStateMachinesList[event]; }
};
AIRegisteredStateMachinesList::AIRegisteredStateMachinesList(void)
{
for (int event = 0; event < AIEvent::number_of_events; ++event)
{
new (&mRegisteredStateMachinesList[event]) AIRegisteredStateMachines;
}
}
// Instantiate the list with all AIRegisteredStateMachines maps.
static AIRegisteredStateMachinesList registered_statemachines_list;
static AIThreadSafeSimpleDC<AIRegisteredStateMachines> registered_statemachines_list[AIEvent::number_of_events];
typedef AIAccess<AIRegisteredStateMachines> registered_statemachines_wat;
//-----------------------------------------------------------------------------
// External API starts here.
@@ -91,7 +77,7 @@ static AIRegisteredStateMachinesList registered_statemachines_list;
void AIEvent::Register(AIEvents event, AIStateMachine* statemachine, bool one_shot)
{
statemachine->idle();
AIAccess<AIRegisteredStateMachines> registered_statemachines_w(registered_statemachines_list[event]);
registered_statemachines_wat registered_statemachines_w(registered_statemachines_list[event]);
registered_statemachines_w->Register(statemachine, one_shot);
}
@@ -99,7 +85,7 @@ void AIEvent::Register(AIEvents event, AIStateMachine* statemachine, bool one_sh
// static
void AIEvent::Unregister(AIEvents event, AIStateMachine* statemachine)
{
AIAccess<AIRegisteredStateMachines> registered_statemachines_w(registered_statemachines_list[event]);
registered_statemachines_wat registered_statemachines_w(registered_statemachines_list[event]);
registered_statemachines_w->Unregister(statemachine);
}
@@ -107,7 +93,7 @@ void AIEvent::Unregister(AIEvents event, AIStateMachine* statemachine)
// static
void AIEvent::trigger(AIEvents event)
{
AIAccess<AIRegisteredStateMachines> registered_statemachines_w(registered_statemachines_list[event]);
registered_statemachines_wat registered_statemachines_w(registered_statemachines_list[event]);
registered_statemachines_w->trigger();
}

View File

@@ -65,7 +65,7 @@ AIFilePicker::AIFilePicker(void) : mPluginManager(NULL), mAutoKill(false), mCanc
}
// static
AITHREADSAFESIMPLE(AIFilePicker::context_map_type, AIFilePicker::sContextMap, );
AIThreadSafeSimpleDC<AIFilePicker::context_map_type> AIFilePicker::sContextMap;
// static
void AIFilePicker::store_folder(std::string const& context, std::string const& folder)

View File

@@ -185,7 +185,7 @@ public:
private:
LLPointer<LLViewerPluginManager> mPluginManager; //!< Pointer to the plugin manager.
typedef std::map<std::string, std::string> context_map_type; //!< Type of mContextMap.
static AIThreadSafeSimple<context_map_type> sContextMap; //!< Map context (ie, "snapshot" or "image") to last used folder.
static AIThreadSafeSimpleDC<context_map_type> sContextMap; //!< Map context (ie, "snapshot" or "image") to last used folder.
std::string mContext; //!< Some key to indicate the context (remembers the folder per key).
bool mAutoKill; //!< True if the default behavior is to delete itself after being finished.

View File

@@ -65,18 +65,18 @@ namespace {
};
typedef std::vector<QueueElement> active_statemachines_type;
static active_statemachines_type active_statemachines;
active_statemachines_type active_statemachines;
typedef std::vector<AIStateMachine*> continued_statemachines_type;
struct cscm_type
{
continued_statemachines_type continued_statemachines;
bool calling_mainloop;
};
static AITHREADSAFE(cscm_type, continued_statemachines_and_calling_mainloop, );
AIThreadSafeDC<cscm_type> continued_statemachines_and_calling_mainloop;
}
// static
AITHREADSAFESIMPLE(U64, AIStateMachine::sMaxCount, );
AIThreadSafeSimpleDC<U64> AIStateMachine::sMaxCount;
void AIStateMachine::updateSettings(void)
{
@@ -157,14 +157,33 @@ void AIStateMachine::idle(void)
mSleep = 0;
}
// About thread safeness:
//
// The main thread initializes a statemachine and calls run, so a statemachine
// runs in the main thread. However, it is allowed that a state calls idle()
// and then allows one and only one other thread to call cont() upon some
// event (only once, of course, as idle() has to be called before cont()
// can be called again-- and another thread is not allowed to call idle()).
// Instead of cont(), the other thread may also call set_state().
void AIStateMachine::cont(void)
{
DoutEntering(dc::statemachine, "AIStateMachine::cont() [" << (void*)this << "]");
llassert(mIdle);
// Atomic test mActive and change mIdle.
mIdleActive.lock();
mIdle = false;
if (mActive == as_idle)
bool not_active = mActive == as_idle;
mIdleActive.unlock();
if (not_active)
{
AIWriteAccess<cscm_type> cscm_w(continued_statemachines_and_calling_mainloop);
// We only get here when the statemachine was idle (set by the main thread),
// see first assertion. Hence, the main thread is not changing this, as the
// statemachine is not running. Thus, mActive can have changed when a THIRD
// thread called cont(), which is not allowed: if two threads can call cont()
// at any moment then the first assertion can't hold.
llassert_always(mActive == as_idle);
cscm_w->continued_statemachines.push_back(this);
if (!cscm_w->calling_mainloop)
{
@@ -173,6 +192,7 @@ void AIStateMachine::cont(void)
gIdleCallbacks.addFunction(&AIStateMachine::mainloop);
}
mActive = as_queued;
llassert_always(!mIdle); // It should never happen that one thread calls cont() while another calls idle() concurrently.
}
}
@@ -203,7 +223,7 @@ void AIStateMachine::finish(void)
{
DoutEntering(dc::statemachine, "AIStateMachine::finish() [" << (void*)this << "]");
llassert(mState == bs_run || mState == bs_abort);
// It is possible that mIdle is false when abort or finish was called from
// It is possible that mIdle is true when abort or finish was called from
// outside multiplex_impl. However, that only may be done by the main thread.
llassert(!mIdle || is_main_thread());
if (!mIdle)
@@ -363,6 +383,9 @@ void AIStateMachine::mainloop(void*)
if (!statemachine.mIdle)
{
U64 start = LLFastTimer::getCPUClockCount64();
// This might call idle() and then pass the statemachine to another thread who then may call cont().
// Hence, after this isn't not sure what mIdle is, and it can change from true to false at any moment,
// if it is true after this function returns.
iter->statemachine().multiplex(start);
U64 delta = LLFastTimer::getCPUClockCount64() - start;
iter->add(delta);
@@ -382,10 +405,23 @@ void AIStateMachine::mainloop(void*)
while (iter != active_statemachines.end())
{
AIStateMachine& statemachine(iter->statemachine());
if (statemachine.mIdle)
// Atomic test mIdle and change mActive.
bool locked = statemachine.mIdleActive.tryLock();
// If the lock failed, then another thread is in the middle of calling cont(),
// thus mIdle will end up false. So, there is no reason to block here; just
// treat mIdle as false already.
if (locked && statemachine.mIdle)
{
Dout(dc::statemachine, "Erasing " << (void*)&statemachine << " from active_statemachines");
// Without the lock, it would be possible that another thread called cont() right here,
// changing mIdle to false again but NOT adding the statemachine to continued_statemachines,
// thinking it is in active_statemachines (and it is), while immediately below it is
// erased from active_statemachines.
statemachine.mActive = as_idle;
// Now, calling cont() is ok -- as that will cause the statemachine to be added to
// continued_statemachines, so it's fine in that case-- even necessary-- to remove it from
// active_statemachines regardless, and we can release the lock here.
statemachine.mIdleActive.unlock();
Dout(dc::statemachine, "Erasing " << (void*)&statemachine << " from active_statemachines");
iter = active_statemachines.erase(iter);
if (statemachine.mState == bs_killed)
{
@@ -395,6 +431,11 @@ void AIStateMachine::mainloop(void*)
}
else
{
if (locked)
{
statemachine.mIdleActive.unlock();
}
llassert(statemachine.mActive == as_active); // It should not be possible that another thread called cont() and changed this when we are we are not idle.
llassert(statemachine.mState == bs_run || statemachine.mState == bs_initialize);
++iter;
}

View File

@@ -206,6 +206,7 @@ class AIStateMachine {
bool mAborted; //!< True after calling abort() and before calling run().
active_type mActive; //!< Whether statemachine is idle, queued to be added to the active list, or already on the active list.
S64 mSleep; //!< Non-zero while the state machine is sleeping.
LLMutex mIdleActive; //!< Used for atomic operations on the pair mIdle / mActive.
// Callback facilities.
// From within an other state machine:
@@ -224,7 +225,7 @@ class AIStateMachine {
};
callback_type* mCallback; //!< Pointer to signal/connection, or NULL when not connected.
static AIThreadSafeSimple<U64> sMaxCount; //!< Number of cpu clocks below which we start a new state machine within the same frame.
static AIThreadSafeSimpleDC<U64> sMaxCount; //!< Number of cpu clocks below which we start a new state machine within the same frame.
protected:
//! State of the derived class. Only valid if mState == bs_run. Call set_state to change.