diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h index 0cff3b77a..e22f587e2 100644 --- a/indra/llcommon/aithreadsafe.h +++ b/indra/llcommon/aithreadsafe.h @@ -49,7 +49,10 @@ template struct AIReadAccessConst; template struct AIReadAccess; template struct AIWriteAccess; +template struct AIAccessConst; template struct AIAccess; +template struct AISTAccessConst; +template struct AISTAccess; #if LL_WINDOWS template class AIThreadSafeBits; @@ -398,6 +401,7 @@ class AIThreadSafeSimple : public AIThreadSafeBits { protected: // Only this one may access the object (through ptr()). + friend struct AIAccessConst; friend struct AIAccess; // Locking control. @@ -509,13 +513,13 @@ public: }; /** - * @brief Write lock object and provide read/write access. + * @brief Write lock object and provide read access. */ template -struct AIAccess +struct AIAccessConst { - //! Construct a AIAccess from a non-constant AIThreadSafeSimple. - AIAccess(AIThreadSafeSimple& wrapper) : mWrapper(wrapper) + //! Construct a AIAccessConst from a constant AIThreadSafeSimple. + AIAccessConst(AIThreadSafeSimple const& wrapper) : mWrapper(const_cast&>(wrapper)) #if AI_NEED_ACCESS_CC , mIsCopyConstructed(false) #endif @@ -524,12 +528,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 +542,204 @@ struct AIAccess } protected: - AIThreadSafeSimple& mWrapper; //!< Reference to the object that we provide access to. + AIThreadSafeSimple& 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 +struct AIAccess : public AIAccessConst +{ + //! Construct a AIAccess from a non-constant AIThreadSafeSimple. + AIAccess(AIThreadSafeSimple& wrapper) : AIAccessConst(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, + * + * + * class Foo { public: Foo(int, int); }; + * + * AITHREADSAFESINGLETHREAD(Foo, foo, (2, 3)); + * + * AISTAccess foo_w(foo); + * // Use foo_w-> for read and write access. + */ +template +class AIThreadSafeSingleThread : public AIThreadSafeBits +{ +protected: + // Only these one may access the object (through ptr()). + friend struct AISTAccessConst; + friend struct AISTAccess; + + // 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::ptr()); + } +}; + +/** + * @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. + * + * For example, instead of + * + * + * Foo foo; + * + * + * One would use + * + * + * AIThreadSafeSingleThreadDC foo; + * + * + * The advantage over AITHREADSAFESINGLETHREAD is that this object can be allocated with + * new on the heap. For example: + * + * + * AIThreadSafeSingleThreadDC* ptr = new AIThreadSafeSingleThreadDC; + * + * + * which is not possible with AITHREADSAFESINGLETHREAD. + */ +template +class AIThreadSafeSingleThreadDC : public AIThreadSafeSingleThread +{ +public: + // Construct a wrapper around a default constructed object. + AIThreadSafeSingleThreadDC(void) { new (AIThreadSafeSingleThread::ptr()) T; } +}; + +/** + * @brief Instantiate a static, global or local object of a given type wrapped in AIThreadSafeSingleThread, using an arbitrary constructor. + * + * For example, instead of doing + * + * + * Foo foo(x, y); + * static Bar bar; + * + * + * One can instantiate a thread-safe instance with + * + * + * AITHREADSAFESINGLETHREAD(Foo, foo, (x, y)); + * static AITHREADSAFESINGLETHREAD(Bar, bar, ); + * + * + * 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 var(new (var.memory()) type paramlist) + +/** + * @brief Access single threaded object for read access. + */ +template +struct AISTAccessConst +{ + //! Construct a AISTAccessConst from a constant AIThreadSafeSingleThread. + AISTAccessConst(AIThreadSafeSingleThread const& wrapper) : mWrapper(const_cast&>(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& 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 +struct AISTAccess : public AISTAccessConst +{ + //! Construct a AISTAccess from a non-constant AIThreadSafeSingleThread. + AISTAccess(AIThreadSafeSingleThread& wrapper) : AISTAccessConst(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 diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index ee7717f12..d16b87cd7 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -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 ; diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index e7c3c53f1..3574e1790 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -113,7 +113,7 @@ typedef LLAtomic32 LLAtomicU32; typedef LLAtomic32 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 +131,7 @@ typedef LLAtomic32 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 +189,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 true if status is an error condition. */ diff --git a/indra/llcommon/llaprpool.cpp b/indra/llcommon/llaprpool.cpp index 03ab406a2..3559ff430 100644 --- a/indra/llcommon/llaprpool.cpp +++ b/indra/llcommon/llaprpool.cpp @@ -1,5 +1,5 @@ /** - * @file LLAPRPool.cpp + * @file llaprpool.cpp * * Copyright (c) 2010, Aleric Inglewood. * diff --git a/indra/llcommon/llaprpool.h b/indra/llcommon/llaprpool.h index aefdaa08b..dc123e942 100644 --- a/indra/llcommon/llaprpool.h +++ b/indra/llcommon/llaprpool.h @@ -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. diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 803db8c3d..433e109d8 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -402,6 +402,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,15 +444,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 diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 2509ecf84..89b6b8d91 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -41,6 +41,9 @@ #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 +77,7 @@ class LL_COMMON_API LLThread private: static U32 sIDIter; static LLAtomicS32 sCount; - + public: typedef enum e_thread_status { @@ -181,15 +184,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: diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 10c3eccaa..e339c9cd4 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1372,13 +1372,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(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(mOffsets[i])); } } else diff --git a/indra/newview/llappviewerlinux_api_dbus.cpp b/indra/newview/llappviewerlinux_api_dbus.cpp index b475eeedb..dfb138c79 100644 --- a/indra/newview/llappviewerlinux_api_dbus.cpp +++ b/indra/newview/llappviewerlinux_api_dbus.cpp @@ -38,6 +38,7 @@ #endif #include "linden_common.h" +#include "llaprpool.h" extern "C" { #include @@ -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,12 +75,12 @@ 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 @@ -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"