summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2011-10-14 11:58:35 -0500
committerDave Parks <davep@lindenlab.com>2011-10-14 11:58:35 -0500
commitc0ca8e5e2e4d3f591db3175f09c0b64b6b2e10c5 (patch)
tree28ea7a212319b0bd452c68e54f374904bfe6ed8a /indra/llcommon
parentfc2929bf4f6366c3a3386e4b79b0fda7bd0466ba (diff)
parent4331c112aba074562e9a8826fe6d271a94f790f0 (diff)
Merge backout of b782a75c99e6
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt3
-rw-r--r--indra/llcommon/llapp.cpp4
-rw-r--r--indra/llcommon/llapr.cpp445
-rw-r--r--indra/llcommon/llapr.h107
-rw-r--r--indra/llcommon/llaprpool.cpp202
-rw-r--r--indra/llcommon/llaprpool.h256
-rw-r--r--indra/llcommon/llcommon.cpp13
-rw-r--r--indra/llcommon/llcommon.h2
-rw-r--r--indra/llcommon/llerror.cpp3
-rw-r--r--indra/llcommon/llerror.h1
-rw-r--r--indra/llcommon/llfixedbuffer.cpp3
-rw-r--r--indra/llcommon/llscopedvolatileaprpool.h52
-rw-r--r--indra/llcommon/llthread.cpp149
-rw-r--r--indra/llcommon/llthread.h134
-rw-r--r--indra/llcommon/llthreadsafequeue.cpp15
-rw-r--r--indra/llcommon/llthreadsafequeue.h16
-rw-r--r--indra/llcommon/llworkerthread.cpp8
-rw-r--r--indra/llcommon/llworkerthread.h3
18 files changed, 613 insertions, 803 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 6f39aba976..0a3eaec5c5 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -31,7 +31,6 @@ set(llcommon_SOURCE_FILES
llallocator_heap_profile.cpp
llapp.cpp
llapr.cpp
- llaprpool.cpp
llassettype.cpp
llavatarname.cpp
llbase32.cpp
@@ -81,7 +80,6 @@ set(llcommon_SOURCE_FILES
llrand.cpp
llrefcount.cpp
llrun.cpp
- llscopedvolatileaprpool.h
llsd.cpp
llsdserialize.cpp
llsdserialize_xml.cpp
@@ -124,7 +122,6 @@ set(llcommon_HEADER_FILES
llavatarname.h
llapp.h
llapr.h
- llaprpool.h
llassettype.h
llassoclist.h
llavatarconstants.h
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index a8b7106078..ed192a9975 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -137,6 +137,10 @@ void LLApp::commonCtor()
mOptions.append(sd);
}
+ // Make sure we clean up APR when we exit
+ // Don't need to do this if we're cleaning up APR in the destructor
+ //atexit(ll_cleanup_apr);
+
// Set the application to this instance.
sApplication = this;
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 1e4a51102e..d1c44c9403 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -29,8 +29,212 @@
#include "linden_common.h"
#include "llapr.h"
#include "apr_dso.h"
-#include "llscopedvolatileaprpool.h"
+apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
+LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
+apr_thread_mutex_t *gLogMutexp = NULL;
+apr_thread_mutex_t *gCallStacksLogMutexp = NULL;
+
+const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool
+
+void ll_init_apr()
+{
+ if (!gAPRPoolp)
+ {
+ // Initialize APR and create the global pool
+ apr_initialize();
+ apr_pool_create(&gAPRPoolp, NULL);
+
+ // Initialize the logging mutex
+ apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
+ apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
+ }
+
+ if(!LLAPRFile::sAPRFilePoolp)
+ {
+ LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;
+ }
+}
+
+
+void ll_cleanup_apr()
+{
+ LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
+
+ if (gLogMutexp)
+ {
+ // Clean up the logging mutex
+
+ // All other threads NEED to be done before we clean up APR, so this is okay.
+ apr_thread_mutex_destroy(gLogMutexp);
+ gLogMutexp = NULL;
+ }
+ if (gCallStacksLogMutexp)
+ {
+ // Clean up the logging mutex
+
+ // All other threads NEED to be done before we clean up APR, so this is okay.
+ apr_thread_mutex_destroy(gCallStacksLogMutexp);
+ gCallStacksLogMutexp = NULL;
+ }
+ if (gAPRPoolp)
+ {
+ apr_pool_destroy(gAPRPoolp);
+ gAPRPoolp = NULL;
+ }
+ if (LLAPRFile::sAPRFilePoolp)
+ {
+ delete LLAPRFile::sAPRFilePoolp ;
+ LLAPRFile::sAPRFilePoolp = NULL ;
+ }
+ apr_terminate();
+}
+
+//
+//
+//LLAPRPool
+//
+LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
+ : mParent(parent),
+ mReleasePoolFlag(releasePoolFlag),
+ mMaxSize(size),
+ mPool(NULL)
+{
+ createAPRPool() ;
+}
+
+LLAPRPool::~LLAPRPool()
+{
+ releaseAPRPool() ;
+}
+
+void LLAPRPool::createAPRPool()
+{
+ if(mPool)
+ {
+ return ;
+ }
+
+ mStatus = apr_pool_create(&mPool, mParent);
+ ll_apr_warn_status(mStatus) ;
+
+ if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes.
+ {
+ apr_allocator_t *allocator = apr_pool_allocator_get(mPool);
+ if (allocator)
+ {
+ apr_allocator_max_free_set(allocator, mMaxSize) ;
+ }
+ }
+}
+
+void LLAPRPool::releaseAPRPool()
+{
+ if(!mPool)
+ {
+ return ;
+ }
+
+ if(!mParent || mReleasePoolFlag)
+ {
+ apr_pool_destroy(mPool) ;
+ mPool = NULL ;
+ }
+}
+
+//virtual
+apr_pool_t* LLAPRPool::getAPRPool()
+{
+ return mPool ;
+}
+
+LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
+ : LLAPRPool(parent, size, releasePoolFlag),
+ mNumActiveRef(0),
+ mNumTotalRef(0),
+ mMutexPool(NULL),
+ mMutexp(NULL)
+{
+ //create mutex
+ if(!is_local) //not a local apr_pool, that is: shared by multiple threads.
+ {
+ apr_pool_create(&mMutexPool, NULL); // Create a pool for mutex
+ apr_thread_mutex_create(&mMutexp, APR_THREAD_MUTEX_UNNESTED, mMutexPool);
+ }
+}
+
+LLVolatileAPRPool::~LLVolatileAPRPool()
+{
+ //delete mutex
+ if(mMutexp)
+ {
+ apr_thread_mutex_destroy(mMutexp);
+ apr_pool_destroy(mMutexPool);
+ }
+}
+
+//
+//define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
+//
+//virtual
+apr_pool_t* LLVolatileAPRPool::getAPRPool()
+{
+ return LLVolatileAPRPool::getVolatileAPRPool() ;
+}
+
+apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()
+{
+ LLScopedLock lock(mMutexp) ;
+
+ mNumTotalRef++ ;
+ mNumActiveRef++ ;
+
+ if(!mPool)
+ {
+ createAPRPool() ;
+ }
+
+ return mPool ;
+}
+
+void LLVolatileAPRPool::clearVolatileAPRPool()
+{
+ LLScopedLock lock(mMutexp) ;
+
+ if(mNumActiveRef > 0)
+ {
+ mNumActiveRef--;
+ if(mNumActiveRef < 1)
+ {
+ if(isFull())
+ {
+ mNumTotalRef = 0 ;
+
+ //destroy the apr_pool.
+ releaseAPRPool() ;
+ }
+ else
+ {
+ //This does not actually free the memory,
+ //it just allows the pool to re-use this memory for the next allocation.
+ apr_pool_clear(mPool) ;
+ }
+ }
+ }
+ else
+ {
+ llassert_always(mNumActiveRef > 0) ;
+ }
+
+ //paranoia check if the pool is jammed.
+ //will remove the check before going to release.
+ llassert_always(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
+}
+
+BOOL LLVolatileAPRPool::isFull()
+{
+ return mNumTotalRef > FULL_VOLATILE_APR_POOL ;
+}
//---------------------------------------------------------------------
//
// LLScopedLock
@@ -109,17 +313,15 @@ void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle)
//
LLAPRFile::LLAPRFile()
: mFile(NULL),
- mVolatileFilePoolp(NULL),
- mRegularFilePoolp(NULL)
+ mCurrentFilePoolp(NULL)
{
}
-LLAPRFile::LLAPRFile(std::string const& filename, apr_int32_t flags, S32* sizep, access_t access_type)
+LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool)
: mFile(NULL),
- mVolatileFilePoolp(NULL),
- mRegularFilePoolp(NULL)
+ mCurrentFilePoolp(NULL)
{
- open(filename, flags, access_type, sizep);
+ open(filename, flags, pool);
}
LLAPRFile::~LLAPRFile()
@@ -136,58 +338,36 @@ apr_status_t LLAPRFile::close()
mFile = NULL ;
}
- if (mVolatileFilePoolp)
+ if(mCurrentFilePoolp)
{
- mVolatileFilePoolp->clearVolatileAPRPool() ;
- mVolatileFilePoolp = NULL ;
- }
-
- if (mRegularFilePoolp)
- {
- delete mRegularFilePoolp;
- mRegularFilePoolp = NULL;
+ mCurrentFilePoolp->clearVolatileAPRPool() ;
+ mCurrentFilePoolp = NULL ;
}
return ret ;
}
-apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, access_t access_type, S32* sizep)
+apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep)
{
- llassert_always(!mFile);
- llassert_always(!mVolatileFilePoolp && !mRegularFilePoolp);
+ apr_status_t s ;
- apr_status_t status;
- {
- 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)
- {
- // Use a "volatile" thread-local pool.
- mVolatileFilePoolp = &LLThreadLocalData::tldata().mVolatileAPRPool;
- // Access the pool and increment its reference count.
- // The reference count of LLVolatileAPRPool objects will be decremented
- // again in LLAPRFile::close by calling mVolatileFilePoolp->clearVolatileAPRPool().
- apr_file_open_pool = mVolatileFilePoolp->getVolatileAPRPool();
- }
- else
- {
- mRegularFilePoolp = new LLAPRPool(LLThreadLocalData::tldata().mRootPool);
- apr_file_open_pool = (*mRegularFilePoolp)();
- }
- status = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_file_open_pool);
- }
- if (status != APR_SUCCESS || !mFile)
+ //check if already open some file
+ llassert_always(!mFile) ;
+ llassert_always(!mCurrentFilePoolp) ;
+
+ apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ;
+ s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool));
+
+ if (s != APR_SUCCESS || !mFile)
{
mFile = NULL ;
- close() ;
+
if (sizep)
{
*sizep = 0;
}
- return status;
}
-
- if (sizep)
+ else if (sizep)
{
S32 file_size = 0;
apr_off_t offset = 0;
@@ -201,7 +381,49 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
*sizep = file_size;
}
- return status;
+ if(!mCurrentFilePoolp)
+ {
+ mCurrentFilePoolp = pool ;
+
+ if(!mFile)
+ {
+ close() ;
+ }
+ }
+
+ return s ;
+}
+
+//use gAPRPoolp.
+apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
+{
+ apr_status_t s;
+
+ //check if already open some file
+ llassert_always(!mFile) ;
+ llassert_always(!mCurrentFilePoolp) ;
+ llassert_always(use_global_pool) ; //be aware of using gAPRPoolp.
+
+ s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp);
+ if (s != APR_SUCCESS || !mFile)
+ {
+ mFile = NULL ;
+ close() ;
+ return s;
+ }
+
+ return s;
+}
+
+apr_pool_t* LLAPRFile::getAPRFilePool(apr_pool_t* pool)
+{
+ if(!pool)
+ {
+ mCurrentFilePoolp = sAPRFilePoolp ;
+ return mCurrentFilePoolp->getVolatileAPRPool() ;
+ }
+
+ return pool ;
}
// File I/O
@@ -260,6 +482,45 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
//
//static
+apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool)
+{
+ apr_status_t ret = APR_SUCCESS ;
+ if(file_handle)
+ {
+ ret = apr_file_close(file_handle);
+ file_handle = NULL ;
+ }
+
+ if(pool)
+ {
+ pool->clearVolatileAPRPool() ;
+ }
+
+ return ret ;
+}
+
+//static
+apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
+{
+ apr_status_t s;
+ apr_file_t* file_handle ;
+
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+
+ s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+ if (s != APR_SUCCESS || !file_handle)
+ {
+ ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL;
+ file_handle = NULL ;
+ close(file_handle, pool) ;
+ return NULL;
+ }
+
+ return file_handle ;
+}
+
+//static
S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
{
if(!file_handle)
@@ -292,15 +553,13 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
}
//static
-S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes)
+S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
{
- apr_file_t* file_handle;
- LLScopedVolatileAPRPool pool;
- apr_status_t s = apr_file_open(&file_handle, filename.c_str(), APR_READ|APR_BINARY, APR_OS_DEFAULT, pool);
- if (s != APR_SUCCESS || !file_handle)
+ //*****************************************
+ apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY);
+ //*****************************************
+ if (!file_handle)
{
- ll_apr_warn_status(s);
- LL_WARNS("APR") << " while attempting to open file \"" << filename << '"' << LL_ENDL;
return 0;
}
@@ -330,13 +589,14 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb
}
}
- apr_file_close(file_handle);
-
+ //*****************************************
+ close(file_handle, pool) ;
+ //*****************************************
return (S32)bytes_read;
}
//static
-S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes)
+S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
{
apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
if (offset < 0)
@@ -345,13 +605,11 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
offset = 0;
}
- apr_file_t* file_handle;
- LLScopedVolatileAPRPool pool;
- apr_status_t s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool);
- if (s != APR_SUCCESS || !file_handle)
+ //*****************************************
+ apr_file_t* file_handle = open(filename, pool, flags);
+ //*****************************************
+ if (!file_handle)
{
- ll_apr_warn_status(s);
- LL_WARNS("APR") << " while attempting to open file \"" << filename << '"' << LL_ENDL;
return 0;
}
@@ -381,18 +639,21 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
}
}
- apr_file_close(file_handle);
+ //*****************************************
+ LLAPRFile::close(file_handle, pool);
+ //*****************************************
return (S32)bytes_written;
}
//static
-bool LLAPRFile::remove(const std::string& filename)
+bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
{
apr_status_t s;
- LLScopedVolatileAPRPool pool;
- s = apr_file_remove(filename.c_str(), pool);
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool());
+ pool->clearVolatileAPRPool() ;
if (s != APR_SUCCESS)
{
@@ -404,12 +665,13 @@ bool LLAPRFile::remove(const std::string& filename)
}
//static
-bool LLAPRFile::rename(const std::string& filename, const std::string& newname)
+bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool)
{
apr_status_t s;
- LLScopedVolatileAPRPool pool;
- s = apr_file_rename(filename.c_str(), newname.c_str(), pool);
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool());
+ pool->clearVolatileAPRPool() ;
if (s != APR_SUCCESS)
{
@@ -421,44 +683,49 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname)
}
//static
-bool LLAPRFile::isExist(const std::string& filename, apr_int32_t flags)
+bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
{
- apr_file_t* file_handle;
+ apr_file_t* apr_file;
apr_status_t s;
- LLScopedVolatileAPRPool pool;
- s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool);
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
- if (s != APR_SUCCESS || !file_handle)
+ if (s != APR_SUCCESS || !apr_file)
{
+ pool->clearVolatileAPRPool() ;
return false;
}
else
{
- apr_file_close(file_handle);
+ apr_file_close(apr_file) ;
+ pool->clearVolatileAPRPool() ;
return true;
}
}
//static
-S32 LLAPRFile::size(const std::string& filename)
+S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool)
{
- apr_file_t* file_handle;
+ apr_file_t* apr_file;
apr_finfo_t info;
apr_status_t s;
- LLScopedVolatileAPRPool pool;
- s = apr_file_open(&file_handle, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool);
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool());
- if (s != APR_SUCCESS || !file_handle)
+ if (s != APR_SUCCESS || !apr_file)
{
+ pool->clearVolatileAPRPool() ;
+
return 0;
}
else
{
- apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, file_handle);
+ apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file);
- apr_file_close(file_handle) ;
+ apr_file_close(apr_file) ;
+ pool->clearVolatileAPRPool() ;
if (s == APR_SUCCESS)
{
@@ -472,29 +739,31 @@ S32 LLAPRFile::size(const std::string& filename)
}
//static
-bool LLAPRFile::makeDir(const std::string& dirname)
+bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool)
{
apr_status_t s;
- LLScopedVolatileAPRPool pool;
- s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool);
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool());
+ pool->clearVolatileAPRPool() ;
if (s != APR_SUCCESS)
{
ll_apr_warn_status(s);
- LL_WARNS("APR") << " while attempting to make directory: " << dirname << LL_ENDL;
+ LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL;
return false;
}
return true;
}
//static
-bool LLAPRFile::removeDir(const std::string& dirname)
+bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool)
{
apr_status_t s;
- LLScopedVolatileAPRPool pool;
- s = apr_file_remove(dirname.c_str(), pool);
+ pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+ s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool());
+ pool->clearVolatileAPRPool() ;
if (s != APR_SUCCESS)
{
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 3f846f1314..af33ce666f 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -50,9 +50,71 @@
#include "apr_atomic.h"
#include "llstring.h"
+extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
+extern apr_thread_mutex_t* gCallStacksLogMutexp;
+
struct apr_dso_handle_t;
-class LLAPRPool;
-class LLVolatileAPRPool;
+
+/**
+ * @brief initialize the common apr constructs -- apr itself, the
+ * global pool, and a mutex.
+ */
+void LL_COMMON_API ll_init_apr();
+
+/**
+ * @brief Cleanup those common apr constructs.
+ */
+void LL_COMMON_API ll_cleanup_apr();
+
+//
+//LL apr_pool
+//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
+//
+class LL_COMMON_API LLAPRPool
+{
+public:
+ LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
+ virtual ~LLAPRPool() ;
+
+ virtual apr_pool_t* getAPRPool() ;
+ apr_status_t getStatus() {return mStatus ; }
+
+protected:
+ void releaseAPRPool() ;
+ void createAPRPool() ;
+
+protected:
+ apr_pool_t* mPool ; //pointing to an apr_pool
+ apr_pool_t* mParent ; //parent pool
+ apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
+ apr_status_t mStatus ; //status when creating the pool
+ BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
+};
+
+//
+//volatile LL apr_pool
+//which clears memory automatically.
+//so it can not hold static data or data after memory is cleared
+//
+class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool
+{
+public:
+ LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
+ virtual ~LLVolatileAPRPool();
+
+ /*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
+ apr_pool_t* getVolatileAPRPool() ;
+ void clearVolatileAPRPool() ;
+
+ BOOL isFull() ;
+
+private:
+ S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
+ S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating.
+
+ apr_thread_mutex_t *mMutexp;
+ apr_pool_t *mMutexPool;
+} ;
/**
* @class LLScopedLock
@@ -143,20 +205,15 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable
// make this non copyable since a copy closes the file
private:
apr_file_t* mFile ;
- LLVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use.
- LLAPRPool* mRegularFilePoolp; // ...or a regular pool.
+ LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool.
public:
- enum access_t {
- long_lived, // Use a global pool for long-lived file accesses.
- short_lived // Use a volatile pool for short-lived file accesses.
- };
-
LLAPRFile() ;
- LLAPRFile(std::string const& filename, apr_int32_t flags, S32* sizep = NULL, access_t access_type = short_lived);
+ LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL);
~LLAPRFile() ;
-
- apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL);
+
+ apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL);
+ apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp.
apr_status_t close() ;
// Returns actual offset, -1 if seek fails
@@ -169,24 +226,32 @@ public:
apr_file_t* getFileHandle() {return mFile;}
+private:
+ apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
+
//
//*******************************************************************************************************************************
//static components
//
+public:
+ static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
+
private:
+ static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
+ static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
public:
// returns false if failure:
- static bool remove(const std::string& filename);
- static bool rename(const std::string& filename, const std::string& newname);
- static bool isExist(const std::string& filename, apr_int32_t flags = APR_READ);
- static S32 size(const std::string& filename);
- static bool makeDir(const std::string& dirname);
- static bool removeDir(const std::string& dirname);
+ static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
+ static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
+ static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
+ static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
+ static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
+ static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
// Returns bytes read/written, 0 if read/write fails:
- static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes);
- static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes); // offset<0 means append
+ static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);
+ static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append
//*******************************************************************************************************************************
};
@@ -202,4 +267,6 @@ bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* han
void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle);
+extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
+
#endif // LL_LLAPR_H
diff --git a/indra/llcommon/llaprpool.cpp b/indra/llcommon/llaprpool.cpp
deleted file mode 100644
index 6f21b61b65..0000000000
--- a/indra/llcommon/llaprpool.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/**
- * @file llaprpool.cpp
- *
- * $LicenseInfo:firstyear=2011&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2011, 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$
- *
- * CHANGELOG
- * and additional copyright holders.
- *
- * 04/04/2010
- * - Initial version, written by Aleric Inglewood @ SL
- *
- * 10/11/2010
- * - Added APR_HAS_THREADS #if's to allow creation and destruction
- * of subpools by threads other than the parent pool owner.
- */
-
-#include "linden_common.h"
-
-#include "llerror.h"
-#include "llaprpool.h"
-#include "llthread.h"
-
-// Create a subpool from parent.
-void LLAPRPool::create(LLAPRPool& parent)
-{
- llassert(!mPool); // Must be non-initialized.
- mParent = &parent;
- if (!mParent) // Using the default parameter?
- {
- // By default use the root pool of the current thread.
- mParent = &LLThreadLocalData::tldata().mRootPool;
- }
- llassert(mParent->mPool); // Parent must be initialized.
-#if APR_HAS_THREADS
- // As per the documentation of APR (ie http://apr.apache.org/docs/apr/1.4/apr__pools_8h.html):
- //
- // Note that most operations on pools are not thread-safe: a single pool should only be
- // accessed by a single thread at any given time. The one exception to this rule is creating
- // a subpool of a given pool: one or more threads can safely create subpools at the same
- // time that another thread accesses the parent pool.
- //
- // In other words, it's safe for any thread to create a (sub)pool, independent of who
- // owns the parent pool.
- mOwner = apr_os_thread_current();
-#else
- mOwner = mParent->mOwner;
- llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
-#endif
- apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, mParent->mPool);
- llassert_always(apr_pool_create_status == APR_SUCCESS);
- llassert(mPool); // Initialized.
- apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null);
-}
-
-// Destroy the (sub)pool, if any.
-void LLAPRPool::destroy(void)
-{
- // Only do anything if we are not already (being) destroyed.
- if (mPool)
- {
-#if !APR_HAS_THREADS
- // If we are a root pool, then every thread may destruct us: in that case
- // we have to assume that no other thread will use this pool concurrently,
- // of course. Otherwise, if we are a subpool, only the thread that owns
- // the parent may destruct us, since that is the pool that is still alive,
- // possibly being used by others and being altered here.
- llassert(!mParent || apr_os_thread_equal(mParent->mOwner, apr_os_thread_current()));
-#endif
- apr_pool_t* pool = mPool; // The use of apr_pool_t is OK here.
- // Temporary store before destroying the pool.
- mPool = NULL; // Mark that we are BEING destructed.
- apr_pool_cleanup_kill(pool, this, &s_plain_cleanup);
- apr_pool_destroy(pool);
- }
-}
-
-bool LLAPRPool::parent_is_being_destructed(void)
-{
- return mParent && (!mParent->mPool || mParent->parent_is_being_destructed());
-}
-
-LLAPRInitialization::LLAPRInitialization(void)
-{
- static bool apr_initialized = false;
-
- if (!apr_initialized)
- {
- apr_initialize();
- }
-
- apr_initialized = true;
-}
-
-bool LLAPRRootPool::sCountInitialized = false;
-apr_uint32_t volatile LLAPRRootPool::sCount;
-
-apr_thread_mutex_t* gLogMutexp;
-apr_thread_mutex_t* gCallStacksLogMutexp;
-
-LLAPRRootPool::LLAPRRootPool(void) : LLAPRInitialization(), LLAPRPool(0)
-{
- // sCountInitialized don't need locking because when we get here there is still only a single thread.
- if (!sCountInitialized)
- {
- // Initialize the logging mutex
- apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool);
- apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool);
-
- apr_status_t status = apr_atomic_init(mPool);
- llassert_always(status == APR_SUCCESS);
- apr_atomic_set32(&sCount, 1); // Set to 1 to account for the global root pool.
- sCountInitialized = true;
-
- // Initialize thread-local APR pool support.
- // Because this recursively calls LLAPRRootPool::LLAPRRootPool(void)
- // it must be done last, so that sCount is already initialized.
- LLThreadLocalData::init();
- }
- apr_atomic_inc32(&sCount);
-}
-
-LLAPRRootPool::~LLAPRRootPool()
-{
- if (!apr_atomic_dec32(&sCount))
- {
- // The last pool was destructed. Cleanup remainder of APR.
- LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
-
- if (gLogMutexp)
- {
- // Clean up the logging mutex
-
- // All other threads NEED to be done before we clean up APR, so this is okay.
- apr_thread_mutex_destroy(gLogMutexp);
- gLogMutexp = NULL;
- }
- if (gCallStacksLogMutexp)
- {
- // Clean up the logging mutex
-
- // All other threads NEED to be done before we clean up APR, so this is okay.
- apr_thread_mutex_destroy(gCallStacksLogMutexp);
- gCallStacksLogMutexp = NULL;
- }
-
- // Must destroy ALL, and therefore this last LLAPRRootPool, before terminating APR.
- static_cast<LLAPRRootPool*>(this)->destroy();
-
- apr_terminate();
- }
-}
-
-//static
-// Return a global root pool that is independent of LLThreadLocalData.
-// Normally you should NOT use this. Only use for early initialization
-// (before main) and deinitialization (after main).
-LLAPRRootPool& LLAPRRootPool::get(void)
-{
- static LLAPRRootPool global_APRpool(0);
- return global_APRpool;
-}
-
-void LLVolatileAPRPool::clearVolatileAPRPool()
-{
- llassert_always(mNumActiveRef > 0);
- if (--mNumActiveRef == 0)
- {
- if (isOld())
- {
- destroy();
- mNumTotalRef = 0 ;
- }
- else
- {
- // This does not actually free the memory,
- // it just allows the pool to re-use this memory for the next allocation.
- clear();
- }
- }
-
- // Paranoia check if the pool is jammed.
- llassert(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
-}
diff --git a/indra/llcommon/llaprpool.h b/indra/llcommon/llaprpool.h
deleted file mode 100644
index bf4102c584..0000000000
--- a/indra/llcommon/llaprpool.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/**
- * @file llaprpool.h
- * @brief Implementation of LLAPRPool
- *
- * $LicenseInfo:firstyear=2011&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2011, 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$
- *
- * CHANGELOG
- * and additional copyright holders.
- *
- * 04/04/2010
- * - Initial version, written by Aleric Inglewood @ SL
- *
- * 10/11/2010
- * - Added APR_HAS_THREADS #if's to allow creation and destruction
- * of subpools by threads other than the parent pool owner.
- *
- * 05/02/2011
- * - Fixed compilation on windows: Suppress compile warning 4996
- * and include <winsock2.h> before including <ws2tcpip.h>,
- * by Merov Linden @ SL.
- */
-
-#ifndef LL_LLAPRPOOL_H
-#define LL_LLAPRPOOL_H
-
-#ifdef LL_WINDOWS
-#pragma warning(push)
-#pragma warning(disable:4996)
-#include <winsock2.h>
-#include <ws2tcpip.h> // Needed before including apr_portable.h
-#pragma warning(pop)
-#endif
-
-#include "apr_portable.h"
-#include "apr_pools.h"
-#include "llerror.h"
-
-extern void ll_init_apr();
-
-/**
- * @brief A wrapper around the APR memory pool API.
- *
- * Usage of this class should be restricted to passing it to libapr-1 function calls that need it.
- *
- */
-class LL_COMMON_API LLAPRPool
-{
-protected:
- //! Pointer to the underlaying pool. NULL if not initialized.
- apr_pool_t* mPool; // The use of apr_pool_t is OK here.
- // This is the wrapped pointer that it is all about!
- //! Pointer to the parent pool, if any. Only valid when mPool is non-zero.
- LLAPRPool* mParent;
- //! The thread that owns this memory pool. Only valid when mPool is non-zero.
- apr_os_thread_t mOwner;
-
-public:
- /// Construct an uninitialized (destructed) pool.
- LLAPRPool(void) : mPool(NULL) { }
-
- /// Construct a subpool from an existing pool.
- /// This is not a copy-constructor, this class doesn't have one!
- LLAPRPool(LLAPRPool& parent) : mPool(NULL) { create(parent); }
-
- /// Destruct the memory pool (free all of its subpools and allocated memory).
- ~LLAPRPool() { destroy(); }
-
-protected:
- /// Create a pool that is allocated from the Operating System. Only used by LLAPRRootPool.
- LLAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current())
- {
- apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL);
- llassert_always(apr_pool_create_status == APR_SUCCESS);
- llassert(mPool);
- apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null);
- }
-
-public:
- /// Create a subpool from parent. May only be called for an uninitialized/destroyed pool.
- /// The default parameter causes the root pool of the current thread to be used.
- void create(LLAPRPool& parent = *static_cast<LLAPRPool*>(NULL));
-
- /// Destroy the (sub)pool, if any.
- void destroy(void);
-
- // Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool.
- typedef LLAPRPool* const LLAPRPool::* const bool_type;
- /// Return true if the pool is initialized.
- operator bool_type() const { return mPool ? &LLAPRPool::mParent : 0; }
-
- /// Painful, but we have to either provide access to this, or wrap
- /// every APR function call that needs an apr pool as argument.
- /// NEVER destroy a pool that is returned by this function!
- apr_pool_t* operator()(void) const // The use of apr_pool_t is OK here.
- // This is the accessor for passing the pool to libapr-1 functions.
- {
- llassert(mPool);
- llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
- return mPool;
- }
-
- /// Free all memory without destructing the pool.
- void clear(void)
- {
- llassert(mPool);
- llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
- apr_pool_clear(mPool);
- }
-
-// These methods would make this class 'complete' (as wrapper around the libapr
-// pool functions), but we don't use memory pools in the viewer (only when
-// we are forced to pass one to a libapr call), so don't define them in order
-// not to encourage people to use them.
-#if 0
- void* palloc(size_t size)
- {
- llassert(mPool);
- llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
- return apr_palloc(mPool, size);
- }
- void* pcalloc(size_t size)
- {
- llassert(mPool);
- llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
- return apr_pcalloc(mPool, size);
- }
-#endif
-
-private:
- bool parent_is_being_destructed(void);
- static apr_status_t s_plain_cleanup(void* userdata) { return static_cast<LLAPRPool*>(userdata)->plain_cleanup(); }
-
- apr_status_t plain_cleanup(void)
- {
- if (mPool && // We are not being destructed,
- parent_is_being_destructed()) // but our parent is.
- // This means the pool is being destructed recursively by libapr
- // because one of its parents is being destructed.
- {
- mPool = NULL; // Stop destroy() from destructing the pool again.
- }
- return APR_SUCCESS;
- }
-};
-
-class LLAPRInitialization
-{
-public:
- LLAPRInitialization(void);
-};
-
-/**
- * @brief Root memory pool (allocates memory from the operating system).
- *
- * This class should only be used by LLThreadLocalData
- * (and LLMutexRootPool when APR_HAS_THREADS isn't defined).
- */
-class LL_COMMON_API LLAPRRootPool : public LLAPRInitialization, public LLAPRPool
-{
-private:
- /// Construct a root memory pool. Should only be used by LLThreadLocalData and LLMutexRootPool.
- friend class LLThreadLocalData;
-#if !APR_HAS_THREADS
- friend class LLMutexRootPool;
-#endif
- /// Construct a root memory pool.
- /// Should only be used by LLThreadLocalData.
- LLAPRRootPool(void);
- ~LLAPRRootPool();
-
-private:
- // Keep track of how many root pools exist and when the last one is destructed.
- static bool sCountInitialized;
- static apr_uint32_t volatile sCount;
-
-public:
- // Return a global root pool that is independent of LLThreadLocalData.
- // Normally you should not use this. Only use for early initialization
- // (before main) and deinitialization (after main).
- static LLAPRRootPool& get(void);
-
-#if APR_POOL_DEBUG
- void grab_ownership(void)
- {
- // You need a patched libapr to use this.
- // See http://web.archiveorange.com/archive/v/5XO9y2zoxUOMt6Gmi1OI
- apr_pool_owner_set(mPool);
- }
-#endif
-
-private:
- // Used for constructing the Special Global Root Pool (returned by LLAPRRootPool::get).
- // It is the same as the default constructor but omits to increment sCount. As a result,
- // we must be sure that at least one other LLAPRRootPool is created before termination
- // of the application (which is the case: we create one LLAPRRootPool per thread).
- LLAPRRootPool(int) : LLAPRInitialization(), LLAPRPool(0) { }
-};
-
-/** Volatile memory pool
- *
- * 'Volatile' APR memory pool which normally only clears memory,
- * and does not destroy the pool (the same pool is reused) for
- * greater efficiency. However, as a safe guard the apr pool
- * is destructed every FULL_VOLATILE_APR_POOL uses to allow
- * the system memory to be allocated more efficiently and not
- * get scattered through RAM.
- */
-class LL_COMMON_API LLVolatileAPRPool : protected LLAPRPool
-{
-public:
- LLVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { }
-
- void clearVolatileAPRPool(void);
-
- bool isOld(void) const { return mNumTotalRef > FULL_VOLATILE_APR_POOL; }
- bool isUnused() const { return mNumActiveRef == 0; }
-
-private:
- friend class LLScopedVolatileAPRPool;
- friend class LLAPRFile;
- apr_pool_t* getVolatileAPRPool(void) // The use of apr_pool_t is OK here.
- {
- if (!mPool) create();
- ++mNumActiveRef;
- ++mNumTotalRef;
- return LLAPRPool::operator()();
- }
-
-private:
- S32 mNumActiveRef; // Number of active uses of the pool.
- S32 mNumTotalRef; // Number of total uses of the pool since last creation.
-
- // Maximum number of references to LLVolatileAPRPool until the pool is recreated.
- static S32 const FULL_VOLATILE_APR_POOL = 1024;
-};
-
-#endif // LL_LLAPRPOOL_H
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index b8a7394852..8be9e4f4de 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -31,9 +31,17 @@
#include "llthread.h"
//static
+BOOL LLCommon::sAprInitialized = FALSE;
+
+//static
void LLCommon::initClass()
{
LLMemory::initClass();
+ if (!sAprInitialized)
+ {
+ ll_init_apr();
+ sAprInitialized = TRUE;
+ }
LLTimer::initClass();
LLThreadSafeRefCount::initThreadSafeRefCount();
// LLWorkerThread::initClass();
@@ -47,5 +55,10 @@ void LLCommon::cleanupClass()
// LLWorkerThread::cleanupClass();
LLThreadSafeRefCount::cleanupThreadSafeRefCount();
LLTimer::cleanupClass();
+ if (sAprInitialized)
+ {
+ ll_cleanup_apr();
+ sAprInitialized = FALSE;
+ }
LLMemory::cleanupClass();
}
diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h
index 171590f3d8..ca9cad5d05 100644
--- a/indra/llcommon/llcommon.h
+++ b/indra/llcommon/llcommon.h
@@ -35,6 +35,8 @@ class LL_COMMON_API LLCommon
public:
static void initClass();
static void cleanupClass();
+private:
+ static BOOL sAprInitialized;
};
#endif
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index bda9d7c177..c35799bbb9 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -866,9 +866,6 @@ You get:
*/
-extern apr_thread_mutex_t* gLogMutexp;
-extern apr_thread_mutex_t* gCallStacksLogMutexp;
-
namespace {
bool checkLevelMap(const LevelMap& map, const std::string& key,
LLError::ELevel& level)
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 369f2a7a97..b3e604f8e8 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -296,4 +296,5 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
Such computation is done iff the message will be logged.
*/
+
#endif // LL_LLERROR_H
diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp
index 4b5cdbe288..d394f179fb 100644
--- a/indra/llcommon/llfixedbuffer.cpp
+++ b/indra/llcommon/llfixedbuffer.cpp
@@ -30,7 +30,8 @@
LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
: LLLineBuffer(),
- mMaxLines(max_lines)
+ mMaxLines(max_lines),
+ mMutex(NULL)
{
mTimer.reset();
}
diff --git a/indra/llcommon/llscopedvolatileaprpool.h b/indra/llcommon/llscopedvolatileaprpool.h
deleted file mode 100644
index dbaf4edcad..0000000000
--- a/indra/llcommon/llscopedvolatileaprpool.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @file llscopedvolatileaprpool.h
- * @brief Implementation of LLScopedVolatileAPRPool
- *
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2011, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLSCOPEDVOLATILEAPRPOOL_H
-#define LL_LLSCOPEDVOLATILEAPRPOOL_H
-
-#include "llthread.h"
-
-/** Scoped volatile memory pool.
- *
- * As the LLVolatileAPRPool should never keep allocations very
- * long, its most common use is for allocations with a lifetime
- * equal to it's scope.
- *
- * This is a convenience class that makes just a little easier to type.
- */
-class LL_COMMON_API LLScopedVolatileAPRPool
-{
-private:
- LLVolatileAPRPool& mPool;
- apr_pool_t* mScopedAPRpool; // The use of apr_pool_t is OK here.
-public:
- LLScopedVolatileAPRPool() : mPool(LLThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { }
- ~LLScopedVolatileAPRPool() { mPool.clearVolatileAPRPool(); }
- //! @attention Only use this to pass the underlaying pointer to a libapr-1 function that requires it.
- operator apr_pool_t*() const { return mScopedAPRpool; } // The use of apr_pool_t is OK here.
-};
-
-#endif
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index bdde1b5c48..ed4f9eb376 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -82,9 +82,6 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
local_thread_ID = threadp->mID;
#endif
- // Create a thread local data.
- LLThreadLocalData::create(threadp);
-
// Run the user supplied function
threadp->run();
@@ -97,22 +94,38 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
}
-LLThread::LLThread(std::string const& name) :
- mPaused(false),
+LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
+ mPaused(FALSE),
mName(name),
mAPRThreadp(NULL),
- mStatus(STOPPED),
- mThreadLocalData(NULL)
+ mStatus(STOPPED)
{
- mID = ++sIDIter; //flaw: assume this is called only in the main thread!
+ // Thread creation probably CAN be paranoid about APR being initialized, if necessary
+ if (poolp)
+ {
+ mIsLocalPool = FALSE;
+ mAPRPoolp = poolp;
+ }
+ else
+ {
+ mIsLocalPool = TRUE;
+ apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
+ }
+ mRunCondition = new LLCondition(mAPRPoolp);
- mRunCondition = new LLCondition;
+ mLocalAPRFilePoolp = NULL ;
}
LLThread::~LLThread()
{
shutdown();
+
+ if(mLocalAPRFilePoolp)
+ {
+ delete mLocalAPRFilePoolp ;
+ mLocalAPRFilePoolp = NULL ;
+ }
}
void LLThread::shutdown()
@@ -159,8 +172,15 @@ void LLThread::shutdown()
delete mRunCondition;
mRunCondition = 0;
+
+ if (mIsLocalPool && mAPRPoolp)
+ {
+ apr_pool_destroy(mAPRPoolp);
+ mAPRPoolp = 0;
+ }
}
+
void LLThread::start()
{
llassert(isStopped());
@@ -169,7 +189,7 @@ void LLThread::start()
mStatus = RUNNING;
apr_status_t status =
- apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool());
+ apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
if(status == APR_SUCCESS)
{
@@ -194,7 +214,7 @@ void LLThread::pause()
if (!mPaused)
{
// this will cause the thread to stop execution as soon as checkPause() is called
- mPaused = true; // Does not need to be atomic since this is only set/unset from the main thread
+ mPaused = 1; // Does not need to be atomic since this is only set/unset from the main thread
}
}
@@ -202,7 +222,7 @@ void LLThread::unpause()
{
if (mPaused)
{
- mPaused = false;
+ mPaused = 0;
}
wake(); // wake up the thread if necessary
@@ -279,76 +299,85 @@ void LLThread::wakeLocked()
}
}
-#ifdef SHOW_ASSERT
-// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread.
-static apr_os_thread_t main_thread_id;
-LL_COMMON_API bool is_main_thread(void) { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); }
-#endif
-
-// The thread private handle to access the LLThreadLocalData instance.
-apr_threadkey_t* LLThreadLocalData::sThreadLocalDataKey;
+//============================================================================
-//static
-void LLThreadLocalData::init(void)
+LLMutex::LLMutex(apr_pool_t *poolp) :
+ mAPRMutexp(NULL)
{
- // Only do this once.
- if (sThreadLocalDataKey)
+ //if (poolp)
+ //{
+ // mIsLocalPool = FALSE;
+ // mAPRPoolp = poolp;
+ //}
+ //else
{
- return;
+ mIsLocalPool = TRUE;
+ apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
}
+ apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
+}
- apr_status_t status = apr_threadkey_private_create(&sThreadLocalDataKey, &LLThreadLocalData::destroy, LLAPRRootPool::get()());
- ll_apr_assert_status(status); // Or out of memory, or system-imposed limit on the
- // total number of keys per process {PTHREAD_KEYS_MAX}
- // has been exceeded.
-
- // Create the thread-local data for the main thread (this function is called by the main thread).
- LLThreadLocalData::create(NULL);
-#ifdef SHOW_ASSERT
- // This function is called by the main thread.
- main_thread_id = apr_os_thread_current();
+LLMutex::~LLMutex()
+{
+#if MUTEX_DEBUG
+ llassert_always(!isLocked()); // better not be locked!
#endif
+ apr_thread_mutex_destroy(mAPRMutexp);
+ mAPRMutexp = NULL;
+ if (mIsLocalPool)
+ {
+ apr_pool_destroy(mAPRPoolp);
+ }
}
-// This is called once for every thread when the thread is destructed.
-//static
-void LLThreadLocalData::destroy(void* thread_local_data)
+
+void LLMutex::lock()
{
- delete static_cast<LLThreadLocalData*>(thread_local_data);
+ apr_thread_mutex_lock(mAPRMutexp);
+#if MUTEX_DEBUG
+ // Have to have the lock before we can access the debug info
+ U32 id = LLThread::currentID();
+ if (mIsLocked[id] != FALSE)
+ llerrs << "Already locked in Thread: " << id << llendl;
+ mIsLocked[id] = TRUE;
+#endif
}
-//static
-void LLThreadLocalData::create(LLThread* threadp)
+void LLMutex::unlock()
{
- LLThreadLocalData* new_tld = new LLThreadLocalData;
- if (threadp)
- {
- threadp->mThreadLocalData = new_tld;
- }
- apr_status_t status = apr_threadkey_private_set(new_tld, sThreadLocalDataKey);
- llassert_always(status == APR_SUCCESS);
+#if MUTEX_DEBUG
+ // Access the debug info while we have the lock
+ U32 id = LLThread::currentID();
+ if (mIsLocked[id] != TRUE)
+ llerrs << "Not locked in Thread: " << id << llendl;
+ mIsLocked[id] = FALSE;
+#endif
+ apr_thread_mutex_unlock(mAPRMutexp);
}
-//static
-LLThreadLocalData& LLThreadLocalData::tldata(void)
+bool LLMutex::isLocked()
{
- if (!sThreadLocalDataKey)
+ apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
+ if (APR_STATUS_IS_EBUSY(status))
{
- LLThreadLocalData::init();
+ return true;
+ }
+ else
+ {
+ apr_thread_mutex_unlock(mAPRMutexp);
+ return false;
}
-
- void* data;
- apr_status_t status = apr_threadkey_private_get(&data, sThreadLocalDataKey);
- llassert_always(status == APR_SUCCESS);
- return *static_cast<LLThreadLocalData*>(data);
}
//============================================================================
-LLCondition::LLCondition(LLAPRPool& parent) : LLMutex(parent)
+LLCondition::LLCondition(apr_pool_t *poolp) :
+ LLMutex(poolp)
{
- apr_thread_cond_create(&mAPRCondp, mPool());
+ // base class (LLMutex) has already ensured that mAPRPoolp is set up.
+
+ apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
}
@@ -424,7 +453,7 @@ void LLThreadSafeRefCount::initThreadSafeRefCount()
{
if (!sMutex)
{
- sMutex = new LLMutex;
+ sMutex = new LLMutex(0);
}
}
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index b631b96252..ad4a6523a1 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -29,13 +29,7 @@
#include "llapp.h"
#include "llapr.h"
-#include "llmemory.h"
#include "apr_thread_cond.h"
-#include "llaprpool.h"
-
-#ifdef SHOW_ASSERT
-extern LL_COMMON_API bool is_main_thread(void);
-#endif
class LLThread;
class LLMutex;
@@ -47,22 +41,6 @@ class LLCondition;
#define ll_thread_local __thread
#endif
-class LL_COMMON_API LLThreadLocalData
-{
-private:
- static apr_threadkey_t* sThreadLocalDataKey;
-
-public:
- // Thread-local memory pools.
- LLAPRRootPool mRootPool;
- LLVolatileAPRPool mVolatileAPRPool;
-
- static void init(void);
- static void destroy(void* thread_local_data);
- static void create(LLThread* pthread);
- static LLThreadLocalData& tldata(void);
-};
-
class LL_COMMON_API LLThread
{
private:
@@ -76,7 +54,7 @@ public:
QUITTING= 2 // Someone wants this thread to quit
} EThreadStatus;
- LLThread(std::string const& name);
+ LLThread(const std::string& name, apr_pool_t *poolp = NULL);
virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state.
virtual void shutdown(); // stops the thread
@@ -91,7 +69,7 @@ public:
// Called from MAIN THREAD.
void pause();
void unpause();
- bool isPaused() { return isStopped() || mPaused; }
+ bool isPaused() { return isStopped() || mPaused == TRUE; }
// Cause the thread to wake up and check its condition
void wake();
@@ -105,11 +83,11 @@ public:
// this kicks off the apr thread
void start(void);
- // Return thread-local data for the current thread.
- static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); }
+ apr_pool_t *getAPRPool() { return mAPRPoolp; }
+ LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
private:
- bool mPaused;
+ BOOL mPaused;
// static function passed to APR thread creation routine
static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap);
@@ -119,11 +97,15 @@ protected:
LLCondition* mRunCondition;
apr_thread_t *mAPRThreadp;
+ apr_pool_t *mAPRPoolp;
+ BOOL mIsLocalPool;
EThreadStatus mStatus;
U32 mID;
- friend void LLThreadLocalData::create(LLThread* threadp);
- LLThreadLocalData* mThreadLocalData;
+ //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
+ //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
+ // otherwise it will cause severe memory leaking!!! --bao
+ LLVolatileAPRPool *mLocalAPRFilePoolp ;
void setQuitting();
@@ -153,90 +135,30 @@ protected:
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
-#ifdef MUTEX_DEBUG
-// We really shouldn't be using recursive locks. Make sure of that in debug mode.
-#define MUTEX_FLAG APR_THREAD_MUTEX_UNNESTED
-#else
-// Use the fastest platform-optimal lock behavior (can be recursive or non-recursive).
-#define MUTEX_FLAG APR_THREAD_MUTEX_DEFAULT
-#endif
-
-class LL_COMMON_API LLMutexBase
-{
-public:
- typedef enum
- {
- NO_THREAD = 0xFFFFFFFF
- } e_locking_thread;
-
- LLMutexBase() ;
-
- void lock() ;
- 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; }
-
-protected:
- // mAPRMutexp is initialized and uninitialized in the derived class.
- apr_thread_mutex_t* mAPRMutexp;
- mutable U32 mCount;
- mutable U32 mLockingThread;
-};
-
-class LL_COMMON_API LLMutex : public LLMutexBase
+class LL_COMMON_API LLMutex
{
public:
- LLMutex(LLAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent)
- {
- apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mPool());
- }
- ~LLMutex()
- {
- //this assertion erroneously triggers whenever an LLCondition is destroyed
- //llassert(!isLocked()); // better not be locked!
- apr_thread_mutex_destroy(mAPRMutexp);
- mAPRMutexp = NULL;
- }
-
+ LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
+ virtual ~LLMutex();
+
+ void lock(); // blocks
+ void unlock();
+ bool isLocked(); // non-blocking, but does do a lock/unlock so not free
+
protected:
- LLAPRPool mPool;
-};
-
-#if APR_HAS_THREADS
-// No need to use a root pool in this case.
-typedef LLMutex LLMutexRootPool;
-#else // APR_HAS_THREADS
-class LL_COMMON_API LLMutexRootPool : public LLMutexBase
-{
-public:
- LLMutexRootPool(void)
- {
- apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mRootPool());
- }
- ~LLMutexRootPool()
- {
-#if APR_POOL_DEBUG
- // It is allowed to destruct root pools from a different thread.
- mRootPool.grab_ownership();
+ apr_thread_mutex_t *mAPRMutexp;
+ apr_pool_t *mAPRPoolp;
+ BOOL mIsLocalPool;
+#if MUTEX_DEBUG
+ std::map<U32, BOOL> mIsLocked;
#endif
- llassert(!isLocked());
- apr_thread_mutex_destroy(mAPRMutexp);
- mAPRMutexp = NULL;
- }
-
-protected:
- LLAPRRootPool mRootPool;
};
-#endif // APR_HAS_THREADS
// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
class LL_COMMON_API LLCondition : public LLMutex
{
public:
- LLCondition(LLAPRPool& parent = LLThread::tldata().mRootPool);
+ LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
~LLCondition();
void wait(); // blocks
@@ -247,10 +169,10 @@ protected:
apr_thread_cond_t *mAPRCondp;
};
-class LL_COMMON_API LLMutexLock
+class LLMutexLock
{
public:
- LLMutexLock(LLMutexBase* mutex)
+ LLMutexLock(LLMutex* mutex)
{
mMutex = mutex;
mMutex->lock();
@@ -260,7 +182,7 @@ public:
mMutex->unlock();
}
private:
- LLMutexBase* mMutex;
+ LLMutex* mMutex;
};
//============================================================================
diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp
index 05d24944f3..8a73e632a9 100644
--- a/indra/llcommon/llthreadsafequeue.cpp
+++ b/indra/llcommon/llthreadsafequeue.cpp
@@ -34,11 +34,19 @@
//-----------------------------------------------------------------------------
-LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(unsigned int capacity):
+LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity):
+ mOwnsPool(pool == 0),
+ mPool(pool),
mQueue(0)
{
- mPool.create();
- apr_status_t status = apr_queue_create(&mQueue, capacity, mPool());
+ if(mOwnsPool) {
+ apr_status_t status = apr_pool_create(&mPool, 0);
+ if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool");
+ } else {
+ ; // No op.
+ }
+
+ apr_status_t status = apr_queue_create(&mQueue, capacity, mPool);
if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue");
}
@@ -51,6 +59,7 @@ LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation()
" elements;" << "memory will be leaked" << LL_ENDL;
apr_queue_term(mQueue);
}
+ if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool);
}
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 43d0b396f2..58cac38769 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -30,9 +30,9 @@
#include <string>
#include <stdexcept>
-#include "llaprpool.h"
+struct apr_pool_t; // From apr_pools.h
class LLThreadSafeQueueImplementation; // See below.
@@ -75,7 +75,7 @@ struct apr_queue_t; // From apr_queue.h
class LL_COMMON_API LLThreadSafeQueueImplementation
{
public:
- LLThreadSafeQueueImplementation(unsigned int capacity);
+ LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity);
~LLThreadSafeQueueImplementation();
void pushFront(void * element);
bool tryPushFront(void * element);
@@ -84,7 +84,8 @@ public:
size_t size();
private:
- LLAPRPool mPool; // The pool used for mQueue.
+ bool mOwnsPool;
+ apr_pool_t * mPool;
apr_queue_t * mQueue;
};
@@ -98,8 +99,9 @@ class LLThreadSafeQueue
public:
typedef ElementT value_type;
- // Constructor.
- LLThreadSafeQueue(unsigned int capacity = 1024);
+ // If the pool is set to NULL one will be allocated and managed by this
+ // queue.
+ LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024);
// Add an element to the front of queue (will block if the queue has
// reached capacity).
@@ -137,8 +139,8 @@ private:
template<typename ElementT>
-LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(unsigned int capacity) :
- mImplementation(capacity)
+LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity):
+ mImplementation(pool, capacity)
{
; // No op.
}
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index e186621503..4988bdf570 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -37,7 +37,12 @@
LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) :
LLQueuedThread(name, threaded, should_pause)
{
- mDeleteMutex = new LLMutex;
+ mDeleteMutex = new LLMutex(NULL);
+
+ if(!mLocalAPRFilePoolp)
+ {
+ mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
+ }
}
LLWorkerThread::~LLWorkerThread()
@@ -199,6 +204,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na
mWorkerClassName(name),
mRequestHandle(LLWorkerThread::nullHandle()),
mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
+ mMutex(NULL),
mWorkFlags(0)
{
if (!mWorkerThread)
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index 973b78ca01..78a4781d15 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -94,6 +94,7 @@ public:
private:
void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
+
};
//============================================================================
@@ -193,7 +194,7 @@ protected:
U32 mRequestPriority; // last priority set
private:
- LLMutexRootPool mMutex; // Use LLMutexRootPool since this object is created and destructed by multiple threads.
+ LLMutex mMutex;
LLAtomicU32 mWorkFlags;
};