Merge remote-tracking branch 'aleric/V2MultiWear' into AltCompilers
This commit is contained in:
@@ -168,19 +168,13 @@ long vfs_tell (void *datasource)
|
|||||||
return file->tell();
|
return file->tell();
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const std::string &out_filename)
|
LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const std::string &out_filename) :
|
||||||
{
|
mValid(FALSE), mDone(FALSE), mBytesRead(-1), mUUID(uuid),
|
||||||
mDone = FALSE;
|
|
||||||
mValid = FALSE;
|
|
||||||
mBytesRead = -1;
|
|
||||||
mUUID = uuid;
|
|
||||||
mInFilep = NULL;
|
|
||||||
mCurrentSection = 0;
|
|
||||||
#if !defined(USE_WAV_VFILE)
|
#if !defined(USE_WAV_VFILE)
|
||||||
mOutFilename = out_filename;
|
mOutFilename(out_filename), mFileHandle(LLLFSThread::nullHandle()),
|
||||||
mFileHandle = LLLFSThread::nullHandle();
|
|
||||||
#endif
|
#endif
|
||||||
// No default value for mVF, it's an ogg structure?
|
mInFilep(NULL), mCurrentSection(0)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVorbisDecodeState::~LLVorbisDecodeState()
|
LLVorbisDecodeState::~LLVorbisDecodeState()
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ set(llcommon_HEADER_FILES
|
|||||||
llaprpool.h
|
llaprpool.h
|
||||||
llassettype.h
|
llassettype.h
|
||||||
llassoclist.h
|
llassoclist.h
|
||||||
|
llatomic.h
|
||||||
llavatarconstants.h
|
llavatarconstants.h
|
||||||
llbase32.h
|
llbase32.h
|
||||||
llbase64.h
|
llbase64.h
|
||||||
|
|||||||
@@ -26,8 +26,65 @@
|
|||||||
*
|
*
|
||||||
* 31/03/2010
|
* 31/03/2010
|
||||||
* Initial version, written by Aleric Inglewood @ SL
|
* 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
|
#ifndef AITHREADSAFE_H
|
||||||
#define AITHREADSAFE_H
|
#define AITHREADSAFE_H
|
||||||
|
|
||||||
@@ -49,15 +106,10 @@
|
|||||||
template<typename T> struct AIReadAccessConst;
|
template<typename T> struct AIReadAccessConst;
|
||||||
template<typename T> struct AIReadAccess;
|
template<typename T> struct AIReadAccess;
|
||||||
template<typename T> struct AIWriteAccess;
|
template<typename T> struct AIWriteAccess;
|
||||||
|
template<typename T> struct AIAccessConst;
|
||||||
template<typename T> struct AIAccess;
|
template<typename T> struct AIAccess;
|
||||||
|
template<typename T> struct AISTAccessConst;
|
||||||
#if LL_WINDOWS
|
template<typename T> struct AISTAccess;
|
||||||
template<typename T> class AIThreadSafeBits;
|
|
||||||
template<typename T>
|
|
||||||
struct AIThreadSafeWindowsHack {
|
|
||||||
AIThreadSafeWindowsHack(AIThreadSafeBits<T>& var, T* object);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class AIThreadSafeBits
|
class AIThreadSafeBits
|
||||||
@@ -80,10 +132,15 @@ public:
|
|||||||
// Only for use by AITHREADSAFE, see below.
|
// Only for use by AITHREADSAFE, see below.
|
||||||
void* memory() const { return const_cast<long*>(&mMemory[0]); }
|
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:
|
protected:
|
||||||
#if LL_WINDOWS
|
|
||||||
template<typename T2> friend struct AIThreadSafeWindowsHack;
|
|
||||||
#endif
|
|
||||||
// Accessors.
|
// Accessors.
|
||||||
T const* ptr() const { return reinterpret_cast<T const*>(mMemory); }
|
T const* ptr() const { return reinterpret_cast<T const*>(mMemory); }
|
||||||
T* ptr() { return reinterpret_cast<T*>(mMemory); }
|
T* ptr() { return reinterpret_cast<T*>(mMemory); }
|
||||||
@@ -185,6 +242,14 @@ public:
|
|||||||
llassert(object == AIThreadSafeBits<T>::ptr());
|
llassert(object == AIThreadSafeBits<T>::ptr());
|
||||||
#endif
|
#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>
|
* <code>
|
||||||
* Foo foo(x, y);
|
* Foo foo(x, y);
|
||||||
* static Bar bar;
|
* static Bar bar(0.1, true);
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* One can instantiate a thread-safe instance with
|
* One can instantiate a thread-safe instance with
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* AITHREADSAFE(Foo, foo, (x, y));
|
* AITHREADSAFE(Foo, foo, (x, y));
|
||||||
* static AITHREADSAFE(Bar, bar, );
|
* static AITHREADSAFE(Bar, bar, (0.1, true));
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* Note: This macro does not allow to allocate such object on the heap.
|
* Note: This macro does not allow to allocate such object on the heap.
|
||||||
* If that is needed, have a look at AIThreadSafeDC.
|
* 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)
|
#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.
|
* @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
|
* 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
|
* For example, instead of
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* Foo foo;
|
* Foo foo;
|
||||||
|
* Bar bar(3);
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* One would use
|
* One would use
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* AIThreadSafeDC<Foo> foo;
|
* AIThreadSafeDC<Foo> foo;
|
||||||
|
* AIThreadSafeDC<Bar> bar(3);
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* The advantage over AITHREADSAFE is that this object can be allocated with
|
* The advantage over AITHREADSAFE is that this object can be allocated with
|
||||||
@@ -253,6 +309,8 @@ class AIThreadSafeDC : public AIThreadSafe<T>
|
|||||||
public:
|
public:
|
||||||
// Construct a wrapper around a default constructed object.
|
// Construct a wrapper around a default constructed object.
|
||||||
AIThreadSafeDC(void) { new (AIThreadSafe<T>::ptr()) T; }
|
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);
|
* AIAccess<Foo> foo_w(foo);
|
||||||
* // Use foo_w-> for read and write access.
|
* // Use foo_w-> for read and write access.
|
||||||
|
* </code>
|
||||||
*
|
*
|
||||||
* See also AIThreadSafe
|
* See also AIThreadSafe
|
||||||
*/
|
*/
|
||||||
@@ -398,6 +457,7 @@ class AIThreadSafeSimple : public AIThreadSafeBits<T>
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
// Only this one may access the object (through ptr()).
|
// Only this one may access the object (through ptr()).
|
||||||
|
friend struct AIAccessConst<T>;
|
||||||
friend struct AIAccess<T>;
|
friend struct AIAccess<T>;
|
||||||
|
|
||||||
// Locking control.
|
// Locking control.
|
||||||
@@ -411,6 +471,14 @@ protected:
|
|||||||
public:
|
public:
|
||||||
// Only for use by AITHREADSAFESIMPLE, see below.
|
// Only for use by AITHREADSAFESIMPLE, see below.
|
||||||
AIThreadSafeSimple(T* object) { llassert(object == AIThreadSafeBits<T>::ptr()); }
|
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>
|
* <code>
|
||||||
* Foo foo(x, y);
|
* Foo foo(x, y);
|
||||||
* static Bar bar;
|
* static Bar bar(0.1, true);
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* One can instantiate a thread-safe instance with
|
* One can instantiate a thread-safe instance with
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* AITHREADSAFESIMPLE(Foo, foo, (x, y));
|
* AITHREADSAFESIMPLE(Foo, foo, (x, y));
|
||||||
* static AITHREADSAFESIMPLE(Bar, bar, );
|
* static AITHREADSAFESIMPLE(Bar, bar, (0.1, true));
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* Note: This macro does not allow to allocate such object on the heap.
|
* 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.
|
* @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
|
* 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
|
* For example, instead of
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* Foo foo;
|
* Foo foo;
|
||||||
|
* Bar bar(0.1);
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* One would use
|
* One would use
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* AIThreadSafeSimpleDC<Foo> foo;
|
* AIThreadSafeSimpleDC<Foo> foo;
|
||||||
|
* AIThreadSafeSimpleDC<Bar> bar(0.1);
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* The advantage over AITHREADSAFESIMPLE is that this object can be allocated with
|
* The advantage over AITHREADSAFESIMPLE is that this object can be allocated with
|
||||||
@@ -468,10 +538,12 @@ class AIThreadSafeSimpleDC : public AIThreadSafeSimple<T>
|
|||||||
public:
|
public:
|
||||||
// Construct a wrapper around a default constructed object.
|
// Construct a wrapper around a default constructed object.
|
||||||
AIThreadSafeSimpleDC(void) { new (AIThreadSafeSimple<T>::ptr()) T; }
|
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:
|
protected:
|
||||||
// For use by AIThreadSafeSimpleDCRootPool
|
// 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
|
// 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>
|
template<typename T>
|
||||||
struct AIAccess
|
struct AIAccessConst
|
||||||
{
|
{
|
||||||
//! Construct a AIAccess from a non-constant AIThreadSafeSimple.
|
//! Construct a AIAccessConst from a constant AIThreadSafeSimple.
|
||||||
AIAccess(AIThreadSafeSimple<T>& wrapper) : mWrapper(wrapper)
|
AIAccessConst(AIThreadSafeSimple<T> const& wrapper) : mWrapper(const_cast<AIThreadSafeSimple<T>&>(wrapper))
|
||||||
#if AI_NEED_ACCESS_CC
|
#if AI_NEED_ACCESS_CC
|
||||||
, mIsCopyConstructed(false)
|
, mIsCopyConstructed(false)
|
||||||
#endif
|
#endif
|
||||||
@@ -524,12 +596,12 @@ struct AIAccess
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Access the underlaying object for (read and) write access.
|
//! 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.
|
//! 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 AI_NEED_ACCESS_CC
|
||||||
if (mIsCopyConstructed) return;
|
if (mIsCopyConstructed) return;
|
||||||
@@ -538,17 +610,229 @@ struct AIAccess
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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
|
#if AI_NEED_ACCESS_CC
|
||||||
bool mIsCopyConstructed;
|
bool mIsCopyConstructed;
|
||||||
public:
|
public:
|
||||||
AIAccess(AIAccess const& orig) : mWrapper(orig.mWrapper), mIsCopyConstructed(true) { }
|
AIAccessConst(AIAccessConst const& orig) : mWrapper(orig.mWrapper), mIsCopyConstructed(true) { }
|
||||||
#else
|
#else
|
||||||
private:
|
private:
|
||||||
// Disallow copy constructing directly.
|
// Disallow copy constructing directly.
|
||||||
AIAccess(AIAccess const&);
|
AIAccessConst(AIAccessConst const&);
|
||||||
#endif
|
#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
|
#endif
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ bool ll_apr_warn_status(apr_status_t status)
|
|||||||
|
|
||||||
void ll_apr_assert_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_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.
|
// This is a temporary variable for a pool that is passed directly to apr_file_open below.
|
||||||
if (access_type == short_lived)
|
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
|
// File I/O
|
||||||
S32 LLAPRFile::read(void *buf, S32 nbytes)
|
S32 LLAPRFile::read(void *buf, S32 nbytes)
|
||||||
{
|
{
|
||||||
//llassert_always(mFile); (ASC-TUDCC) -HgB
|
|
||||||
if(!mFile)
|
if(!mFile)
|
||||||
{
|
{
|
||||||
llwarns << "apr mFile is removed by somebody else. Can not read." << llendl ;
|
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)
|
S32 LLAPRFile::write(const void *buf, S32 nbytes)
|
||||||
{
|
{
|
||||||
// llassert_always(mFile); (ASC-TUDCC) -HgB
|
|
||||||
if(!mFile)
|
if(!mFile)
|
||||||
{
|
{
|
||||||
llwarns << "apr mFile is removed by somebody else. Can not write." << llendl ;
|
llwarns << "apr mFile is removed by somebody else. Can not write." << llendl ;
|
||||||
|
|||||||
@@ -91,29 +91,8 @@ protected:
|
|||||||
apr_thread_mutex_t* mMutex;
|
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.
|
// 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
|
// abbreviated flags
|
||||||
#define LL_APR_R (APR_READ) // "r"
|
#define LL_APR_R (APR_READ) // "r"
|
||||||
#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w"
|
#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().
|
// especially do not put some time-costly operations between open() and close().
|
||||||
// otherwise it might lock the APRFilePool.
|
// otherwise it might lock the APRFilePool.
|
||||||
//there are two different apr_pools the APRFile can use:
|
//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.
|
// 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.
|
* APR_SUCCESS.
|
||||||
* @return Returns <code>true</code> if status is an error condition.
|
* @return Returns <code>true</code> if status is an error condition.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file LLAPRPool.cpp
|
* @file llaprpool.cpp
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Aleric Inglewood.
|
* Copyright (c) 2010, Aleric Inglewood.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file LLAPRPool.h
|
* @file llaprpool.h
|
||||||
* @brief Implementation of LLAPRPool.
|
* @brief Implementation of LLAPRPool.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Aleric Inglewood.
|
* Copyright (c) 2010, Aleric Inglewood.
|
||||||
@@ -60,9 +60,9 @@ extern void ll_init_apr();
|
|||||||
class LL_COMMON_API LLAPRPool
|
class LL_COMMON_API LLAPRPool
|
||||||
{
|
{
|
||||||
protected:
|
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.
|
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:
|
public:
|
||||||
//! Construct an uninitialized (destructed) pool.
|
//! Construct an uninitialized (destructed) pool.
|
||||||
|
|||||||
61
indra/llcommon/llatomic.h
Normal file
61
indra/llcommon/llatomic.h
Normal 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
|
||||||
@@ -39,7 +39,6 @@ void LLCommon::initClass()
|
|||||||
{
|
{
|
||||||
LLMemory::initClass();
|
LLMemory::initClass();
|
||||||
LLTimer::initClass();
|
LLTimer::initClass();
|
||||||
LLThreadSafeRefCount::initThreadSafeRefCount();
|
|
||||||
// LLWorkerThread::initClass();
|
// LLWorkerThread::initClass();
|
||||||
// LLFrameCallbackManager::initClass();
|
// LLFrameCallbackManager::initClass();
|
||||||
}
|
}
|
||||||
@@ -49,7 +48,6 @@ void LLCommon::cleanupClass()
|
|||||||
{
|
{
|
||||||
// LLFrameCallbackManager::cleanupClass();
|
// LLFrameCallbackManager::cleanupClass();
|
||||||
// LLWorkerThread::cleanupClass();
|
// LLWorkerThread::cleanupClass();
|
||||||
LLThreadSafeRefCount::cleanupThreadSafeRefCount();
|
|
||||||
LLTimer::cleanupClass();
|
LLTimer::cleanupClass();
|
||||||
LLMemory::cleanupClass();
|
LLMemory::cleanupClass();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class LLSD;
|
|||||||
class LLOptionInterface
|
class LLOptionInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~LLOptionInterface() = 0;
|
virtual ~LLOptionInterface();
|
||||||
virtual LLSD getOption(const std::string& name) const = 0;
|
virtual LLSD getOption(const std::string& name) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
#include "llsimplehash.h"
|
#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.
|
// It is assumed that LLQueuedThreads are rarely created/destroyed.
|
||||||
|
|
||||||
class LL_COMMON_API LLQueuedThread : public LLThread
|
class LL_COMMON_API LLQueuedThread : public LLThread
|
||||||
|
|||||||
@@ -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.
|
// the moment it happens... therefore make a copy here.
|
||||||
char const* volatile name = threadp->mName.c_str();
|
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.
|
// We're done with the run function, this thread is done executing now.
|
||||||
threadp->mStatus = STOPPED;
|
threadp->mStatus = STOPPED;
|
||||||
|
|
||||||
@@ -178,7 +183,7 @@ void LLThread::shutdown()
|
|||||||
}
|
}
|
||||||
mAPRThreadp = NULL;
|
mAPRThreadp = NULL;
|
||||||
}
|
}
|
||||||
sCount--;
|
--sCount;
|
||||||
delete mRunCondition;
|
delete mRunCondition;
|
||||||
mRunCondition = 0;
|
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()
|
void LLMutexBase::lock()
|
||||||
{
|
{
|
||||||
#if LL_DARWIN
|
#if LL_DARWIN
|
||||||
@@ -435,37 +449,6 @@ void LLMutexBase::unlock()
|
|||||||
apr_thread_mutex_unlock(mAPRMutexp);
|
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() :
|
LLThreadSafeRefCount::LLThreadSafeRefCount() :
|
||||||
|
|||||||
@@ -38,9 +38,13 @@
|
|||||||
#include "llmemory.h"
|
#include "llmemory.h"
|
||||||
#include "apr_thread_cond.h"
|
#include "apr_thread_cond.h"
|
||||||
#include "llaprpool.h"
|
#include "llaprpool.h"
|
||||||
|
#include "llatomic.h"
|
||||||
|
|
||||||
#ifdef SHOW_ASSERT
|
#ifdef SHOW_ASSERT
|
||||||
extern LL_COMMON_API bool is_main_thread(void);
|
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
|
#endif
|
||||||
|
|
||||||
class LLThread;
|
class LLThread;
|
||||||
@@ -74,7 +78,7 @@ class LL_COMMON_API LLThread
|
|||||||
private:
|
private:
|
||||||
static U32 sIDIter;
|
static U32 sIDIter;
|
||||||
static LLAtomicS32 sCount;
|
static LLAtomicS32 sCount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef enum e_thread_status
|
typedef enum e_thread_status
|
||||||
{
|
{
|
||||||
@@ -181,15 +185,18 @@ public:
|
|||||||
|
|
||||||
LLMutexBase() ;
|
LLMutexBase() ;
|
||||||
|
|
||||||
void lock(); //blocks
|
void lock(); // blocks
|
||||||
void unlock();
|
void unlock();
|
||||||
// Returns true if lock was obtained successfully.
|
// Returns true if lock was obtained successfully.
|
||||||
bool tryLock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); }
|
bool tryLock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); }
|
||||||
|
|
||||||
// non-blocking, but does do a lock/unlock so not free
|
// 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; }
|
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
|
// get ID of locking thread
|
||||||
bool isSelfLocked(); //return true if locked in a same thread
|
|
||||||
U32 lockingThread() const { return mLockingThread; }
|
U32 lockingThread() const { return mLockingThread; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -394,13 +401,6 @@ void LLThread::unlockData()
|
|||||||
|
|
||||||
class LL_COMMON_API LLThreadSafeRefCount
|
class LL_COMMON_API LLThreadSafeRefCount
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
static void initThreadSafeRefCount(); // creates sMutex
|
|
||||||
static void cleanupThreadSafeRefCount(); // destroys sMutex
|
|
||||||
|
|
||||||
private:
|
|
||||||
static LLMutex* sMutex;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented
|
LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented
|
||||||
LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented
|
LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented
|
||||||
@@ -413,31 +413,20 @@ public:
|
|||||||
|
|
||||||
void ref()
|
void ref()
|
||||||
{
|
{
|
||||||
if (sMutex) sMutex->lock();
|
|
||||||
mRef++;
|
mRef++;
|
||||||
if (sMutex) sMutex->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
S32 unref()
|
void unref()
|
||||||
{
|
{
|
||||||
llassert(mRef >= 1);
|
if (!--mRef) delete this;
|
||||||
if (sMutex) sMutex->lock();
|
}
|
||||||
S32 res = --mRef;
|
|
||||||
if (sMutex) sMutex->unlock();
|
|
||||||
if (0 == res)
|
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
S32 getNumRefs() const
|
S32 getNumRefs() const
|
||||||
{
|
{
|
||||||
return mRef;
|
return mRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
S32 mRef;
|
LLAtomicS32 mRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ U8* LLImageBase::allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 si
|
|||||||
// LLImageRaw
|
// LLImageRaw
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
AITHREADSAFESIMPLE(S32, LLImageRaw::sGlobalRawMemory, );
|
AIThreadSafeSimpleDC<S32> LLImageRaw::sGlobalRawMemory;
|
||||||
S32 LLImageRaw::sRawImageCount = 0;
|
S32 LLImageRaw::sRawImageCount = 0;
|
||||||
S32 LLImageRaw::sRawImageCachedCount = 0;
|
S32 LLImageRaw::sRawImageCachedCount = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ protected:
|
|||||||
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
|
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static AIThreadSafeSimple<S32> sGlobalRawMemory;
|
static AIThreadSafeSimpleDC<S32> sGlobalRawMemory;
|
||||||
static S32 sRawImageCount;
|
static S32 sRawImageCount;
|
||||||
|
|
||||||
static S32 sRawImageCachedCount;
|
static S32 sRawImageCachedCount;
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ set(llmessage_SOURCE_FILES
|
|||||||
lldispatcher.cpp
|
lldispatcher.cpp
|
||||||
llfiltersd2xmlrpc.cpp
|
llfiltersd2xmlrpc.cpp
|
||||||
llhost.cpp
|
llhost.cpp
|
||||||
llhttpassetstorage.cpp
|
|
||||||
llhttpclient.cpp
|
llhttpclient.cpp
|
||||||
llhttpclientadapter.cpp
|
llhttpclientadapter.cpp
|
||||||
llhttpnode.cpp
|
llhttpnode.cpp
|
||||||
@@ -125,7 +124,6 @@ set(llmessage_HEADER_FILES
|
|||||||
llfiltersd2xmlrpc.h
|
llfiltersd2xmlrpc.h
|
||||||
llfollowcamparams.h
|
llfollowcamparams.h
|
||||||
llhost.h
|
llhost.h
|
||||||
llhttpassetstorage.h
|
|
||||||
llhttpclient.h
|
llhttpclient.h
|
||||||
llhttpclientinterface.h
|
llhttpclientinterface.h
|
||||||
llhttpclientadapter.h
|
llhttpclientadapter.h
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
|
||||||
@@ -99,7 +99,22 @@ int LLPluginInstance::load(std::string &plugin_file)
|
|||||||
if(result != APR_SUCCESS)
|
if(result != APR_SUCCESS)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
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)
|
#if LL_LINUX && defined(LL_STANDALONE)
|
||||||
LL_WARNS("Plugin") << "plugin load " << plugin_file << " failed with error " << result << " , additional info string: " << buf << LL_ENDL;
|
LL_WARNS("Plugin") << "plugin load " << plugin_file << " failed with error " << result << " , additional info string: " << buf << LL_ENDL;
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ int main(int argc, char **argv)
|
|||||||
#ifdef CWDEBUG
|
#ifdef CWDEBUG
|
||||||
Debug( libcw_do.margin().assign("SLPlugin ", 9) );
|
Debug( libcw_do.margin().assign("SLPlugin ", 9) );
|
||||||
Debug(debug::init());
|
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());
|
//Debug(attach_gdb());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1400,13 +1400,13 @@ void LLVertexBuffer::setupVertexArray()
|
|||||||
//glVertexattribIPointer requires GLSL 1.30 or later
|
//glVertexattribIPointer requires GLSL 1.30 or later
|
||||||
if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30)
|
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
|
#endif
|
||||||
}
|
}
|
||||||
else
|
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
|
else
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
|
#include "llaprpool.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <dbus/dbus-glib.h>
|
#include <dbus/dbus-glib.h>
|
||||||
@@ -55,8 +56,8 @@ extern "C" {
|
|||||||
#undef LL_DBUS_SYM
|
#undef LL_DBUS_SYM
|
||||||
|
|
||||||
static bool sSymsGrabbed = false;
|
static bool sSymsGrabbed = false;
|
||||||
static apr_pool_t *sSymDBUSDSOMemoryPool = NULL;
|
static LLAPRPool sSymDBUSDSOMemoryPool; // Used for sSymDBUSDSOHandleG (and what it is pointing at?)
|
||||||
static apr_dso_handle_t *sSymDBUSDSOHandleG = NULL;
|
static apr_dso_handle_t* sSymDBUSDSOHandleG = NULL;
|
||||||
|
|
||||||
bool grab_dbus_syms(std::string dbus_dso_name)
|
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)
|
#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
|
//attempt to load the shared library
|
||||||
apr_pool_create(&sSymDBUSDSOMemoryPool, NULL);
|
sSymDBUSDSOMemoryPool.create();
|
||||||
|
|
||||||
#ifdef LL_STANDALONE
|
#ifdef LL_STANDALONE
|
||||||
void *dso_handle = dlopen(dbus_dso_name.c_str(), RTLD_NOW | RTLD_GLOBAL);
|
void *dso_handle = dlopen(dbus_dso_name.c_str(), RTLD_NOW | RTLD_GLOBAL);
|
||||||
rv = (!dso_handle)?APR_EDSOOPEN:apr_os_dso_handle_put(&sSymDBUSDSOHandle,
|
rv = (!dso_handle)?APR_EDSOOPEN:apr_os_dso_handle_put(&sSymDBUSDSOHandle,
|
||||||
dso_handle, sSymDBUSDSOMemoryPool);
|
dso_handle, sSymDBUSDSOMemoryPool());
|
||||||
|
|
||||||
if ( APR_SUCCESS == rv )
|
if ( APR_SUCCESS == rv )
|
||||||
#else
|
#else
|
||||||
if ( APR_SUCCESS == (rv = apr_dso_load(&sSymDBUSDSOHandle,
|
if ( APR_SUCCESS == (rv = apr_dso_load(&sSymDBUSDSOHandle,
|
||||||
dbus_dso_name.c_str(),
|
dbus_dso_name.c_str(),
|
||||||
sSymDBUSDSOMemoryPool) ))
|
sSymDBUSDSOMemoryPool()) ))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
INFOMSG("Found DSO: %s", dbus_dso_name.c_str());
|
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
|
#undef LL_DBUS_SYM
|
||||||
|
|
||||||
sSymsGrabbed = rtn;
|
sSymsGrabbed = rtn;
|
||||||
|
if (!sSymsGrabbed)
|
||||||
|
{
|
||||||
|
sSymDBUSDSOMemoryPool.destroy();
|
||||||
|
}
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,13 +132,9 @@ void ungrab_dbus_syms()
|
|||||||
apr_dso_unload(sSymDBUSDSOHandleG);
|
apr_dso_unload(sSymDBUSDSOHandleG);
|
||||||
sSymDBUSDSOHandleG = NULL;
|
sSymDBUSDSOHandleG = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sSymDBUSDSOMemoryPool )
|
sSymDBUSDSOMemoryPool.destroy();
|
||||||
{
|
|
||||||
apr_pool_destroy(sSymDBUSDSOMemoryPool);
|
|
||||||
sSymDBUSDSOMemoryPool = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NULL-out all of the symbols we'd grabbed
|
// NULL-out all of the symbols we'd grabbed
|
||||||
#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{ll##DBUSSYM = NULL;}while(0)
|
#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{ll##DBUSSYM = NULL;}while(0)
|
||||||
#include "llappviewerlinux_api_dbus_syms_raw.inc"
|
#include "llappviewerlinux_api_dbus_syms_raw.inc"
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
BOOL gHackGodmode = FALSE;
|
BOOL gHackGodmode = FALSE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AITHREADSAFE(settings_map_type, gSettings,);
|
AIThreadSafeDC<settings_map_type> gSettings;
|
||||||
LLControlGroup gSavedSettings("Global"); // saved at end of session
|
LLControlGroup gSavedSettings("Global"); // saved at end of session
|
||||||
LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session
|
LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session
|
||||||
LLControlGroup gColors("Colors"); // saved at end of session
|
LLControlGroup gColors("Colors"); // saved at end of session
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ extern BOOL gHackGodmode;
|
|||||||
void settings_setup_listeners();
|
void settings_setup_listeners();
|
||||||
|
|
||||||
typedef std::map<std::string, LLControlGroup*> settings_map_type;
|
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
|
// for the graphics settings
|
||||||
void create_graphics_group(LLControlGroup& group);
|
void create_graphics_group(LLControlGroup& group);
|
||||||
|
|||||||
@@ -64,22 +64,8 @@ inline void AIRegisteredStateMachines::trigger(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A list (array) with all AIRegisteredStateMachines maps, one for each event type.
|
// A list (array) with all AIRegisteredStateMachines maps, one for each event type.
|
||||||
struct AIRegisteredStateMachinesList {
|
static AIThreadSafeSimpleDC<AIRegisteredStateMachines> registered_statemachines_list[AIEvent::number_of_events];
|
||||||
AIThreadSafeSimple<AIRegisteredStateMachines> mRegisteredStateMachinesList[AIEvent::number_of_events];
|
typedef AIAccess<AIRegisteredStateMachines> registered_statemachines_wat;
|
||||||
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;
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// External API starts here.
|
// External API starts here.
|
||||||
@@ -91,7 +77,7 @@ static AIRegisteredStateMachinesList registered_statemachines_list;
|
|||||||
void AIEvent::Register(AIEvents event, AIStateMachine* statemachine, bool one_shot)
|
void AIEvent::Register(AIEvents event, AIStateMachine* statemachine, bool one_shot)
|
||||||
{
|
{
|
||||||
statemachine->idle();
|
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);
|
registered_statemachines_w->Register(statemachine, one_shot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +85,7 @@ void AIEvent::Register(AIEvents event, AIStateMachine* statemachine, bool one_sh
|
|||||||
// static
|
// static
|
||||||
void AIEvent::Unregister(AIEvents event, AIStateMachine* statemachine)
|
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);
|
registered_statemachines_w->Unregister(statemachine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +93,7 @@ void AIEvent::Unregister(AIEvents event, AIStateMachine* statemachine)
|
|||||||
// static
|
// static
|
||||||
void AIEvent::trigger(AIEvents event)
|
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();
|
registered_statemachines_w->trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ AIFilePicker::AIFilePicker(void) : mPluginManager(NULL), mAutoKill(false), mCanc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
AITHREADSAFESIMPLE(AIFilePicker::context_map_type, AIFilePicker::sContextMap, );
|
AIThreadSafeSimpleDC<AIFilePicker::context_map_type> AIFilePicker::sContextMap;
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void AIFilePicker::store_folder(std::string const& context, std::string const& folder)
|
void AIFilePicker::store_folder(std::string const& context, std::string const& folder)
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
LLPointer<LLViewerPluginManager> mPluginManager; //!< Pointer to the plugin manager.
|
LLPointer<LLViewerPluginManager> mPluginManager; //!< Pointer to the plugin manager.
|
||||||
typedef std::map<std::string, std::string> context_map_type; //!< Type of mContextMap.
|
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).
|
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.
|
bool mAutoKill; //!< True if the default behavior is to delete itself after being finished.
|
||||||
|
|
||||||
|
|||||||
@@ -65,18 +65,18 @@ namespace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<QueueElement> active_statemachines_type;
|
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;
|
typedef std::vector<AIStateMachine*> continued_statemachines_type;
|
||||||
struct cscm_type
|
struct cscm_type
|
||||||
{
|
{
|
||||||
continued_statemachines_type continued_statemachines;
|
continued_statemachines_type continued_statemachines;
|
||||||
bool calling_mainloop;
|
bool calling_mainloop;
|
||||||
};
|
};
|
||||||
static AITHREADSAFE(cscm_type, continued_statemachines_and_calling_mainloop, );
|
AIThreadSafeDC<cscm_type> continued_statemachines_and_calling_mainloop;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
AITHREADSAFESIMPLE(U64, AIStateMachine::sMaxCount, );
|
AIThreadSafeSimpleDC<U64> AIStateMachine::sMaxCount;
|
||||||
|
|
||||||
void AIStateMachine::updateSettings(void)
|
void AIStateMachine::updateSettings(void)
|
||||||
{
|
{
|
||||||
@@ -157,14 +157,33 @@ void AIStateMachine::idle(void)
|
|||||||
mSleep = 0;
|
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)
|
void AIStateMachine::cont(void)
|
||||||
{
|
{
|
||||||
DoutEntering(dc::statemachine, "AIStateMachine::cont() [" << (void*)this << "]");
|
DoutEntering(dc::statemachine, "AIStateMachine::cont() [" << (void*)this << "]");
|
||||||
llassert(mIdle);
|
llassert(mIdle);
|
||||||
|
// Atomic test mActive and change mIdle.
|
||||||
|
mIdleActive.lock();
|
||||||
mIdle = false;
|
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);
|
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);
|
cscm_w->continued_statemachines.push_back(this);
|
||||||
if (!cscm_w->calling_mainloop)
|
if (!cscm_w->calling_mainloop)
|
||||||
{
|
{
|
||||||
@@ -173,6 +192,7 @@ void AIStateMachine::cont(void)
|
|||||||
gIdleCallbacks.addFunction(&AIStateMachine::mainloop);
|
gIdleCallbacks.addFunction(&AIStateMachine::mainloop);
|
||||||
}
|
}
|
||||||
mActive = as_queued;
|
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 << "]");
|
DoutEntering(dc::statemachine, "AIStateMachine::finish() [" << (void*)this << "]");
|
||||||
llassert(mState == bs_run || mState == bs_abort);
|
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.
|
// outside multiplex_impl. However, that only may be done by the main thread.
|
||||||
llassert(!mIdle || is_main_thread());
|
llassert(!mIdle || is_main_thread());
|
||||||
if (!mIdle)
|
if (!mIdle)
|
||||||
@@ -363,6 +383,9 @@ void AIStateMachine::mainloop(void*)
|
|||||||
if (!statemachine.mIdle)
|
if (!statemachine.mIdle)
|
||||||
{
|
{
|
||||||
U64 start = LLFastTimer::getCPUClockCount64();
|
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);
|
iter->statemachine().multiplex(start);
|
||||||
U64 delta = LLFastTimer::getCPUClockCount64() - start;
|
U64 delta = LLFastTimer::getCPUClockCount64() - start;
|
||||||
iter->add(delta);
|
iter->add(delta);
|
||||||
@@ -382,10 +405,23 @@ void AIStateMachine::mainloop(void*)
|
|||||||
while (iter != active_statemachines.end())
|
while (iter != active_statemachines.end())
|
||||||
{
|
{
|
||||||
AIStateMachine& statemachine(iter->statemachine());
|
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;
|
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);
|
iter = active_statemachines.erase(iter);
|
||||||
if (statemachine.mState == bs_killed)
|
if (statemachine.mState == bs_killed)
|
||||||
{
|
{
|
||||||
@@ -395,6 +431,11 @@ void AIStateMachine::mainloop(void*)
|
|||||||
}
|
}
|
||||||
else
|
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);
|
llassert(statemachine.mState == bs_run || statemachine.mState == bs_initialize);
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ class AIStateMachine {
|
|||||||
bool mAborted; //!< True after calling abort() and before calling run().
|
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.
|
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.
|
S64 mSleep; //!< Non-zero while the state machine is sleeping.
|
||||||
|
LLMutex mIdleActive; //!< Used for atomic operations on the pair mIdle / mActive.
|
||||||
|
|
||||||
// Callback facilities.
|
// Callback facilities.
|
||||||
// From within an other state machine:
|
// From within an other state machine:
|
||||||
@@ -224,7 +225,7 @@ class AIStateMachine {
|
|||||||
};
|
};
|
||||||
callback_type* mCallback; //!< Pointer to signal/connection, or NULL when not connected.
|
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:
|
protected:
|
||||||
//! State of the derived class. Only valid if mState == bs_run. Call set_state to change.
|
//! State of the derived class. Only valid if mState == bs_run. Call set_state to change.
|
||||||
|
|||||||
Reference in New Issue
Block a user