summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorAleric Inglewood <Aleric.Inglewood@gmail.com>2011-02-05 15:58:07 +0100
committerAleric Inglewood <Aleric.Inglewood@gmail.com>2011-02-05 15:58:07 +0100
commitef490e308ccce8e6df85144784a0f4580f5ac6a1 (patch)
tree98756a6172e2335626babf160908e52dd446ed63 /indra/llcommon
parent09b009fc23e75c8403cc9879f7f839d9e2656c02 (diff)
Introduces a LLThreadLocalData class that can be
accessed through the static LLThread::tldata(). Currently this object contains two (public) thread-local objects: a LLAPRRootPool and a LLVolatileAPRPool. The first is the general memory pool used by this thread (and this thread alone), while the second is intended for short lived memory allocations (needed for APR). The advantages of not mixing those two is that the latter is used most frequently, and as a result of it's nature can be destroyed and reconstructed on a "regular" basis. This patch adds LLAPRPool (completely replacing the old one), which is a wrapper around apr_pool_t* and has complete thread-safity checking. Whenever an apr call requires memory for some resource, a memory pool in the form of an LLAPRPool object can be created with the same life-time as this resource; assuring clean up of the memory no sooner, but also not much later than the life-time of the resource that needs the memory. Many, many function calls and constructors had the pool parameter simply removed (it is no longer the concern of the developer, if you don't write code that actually does an libapr call then you are no longer bothered with memory pools at all). However, I kept the notion of short-lived and long-lived allocations alive (see my remark in the jira here: https://jira.secondlife.com/browse/STORM-864?focusedCommentId=235356&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-235356 which requires that the LLAPRFile API needs to allow the user to specify how long they think a file will stay open. By choosing 'short_lived' as default for the constructor that immediately opens a file, the number of instances where this needs to be specified is drastically reduced however (obviously, any automatic LLAPRFile is short lived). *** Addressed Boroondas remarks in https://codereview.secondlife.com/r/99/ regarding (doxygen) comments. This patch effectively only changes comments. Includes some 'merge' stuff that ended up in llvocache.cpp (while starting as a bug fix, now only resulting in a cleanup). *** Added comment 'The use of apr_pool_t is OK here'. Added this comment on every line where apr_pool_t is correctly being used. This should make it easier to spot (future) errors where someone started to use apr_pool_t; you can just grep all sources for 'apr_pool_t' and immediately see where it's being used while LLAPRPool should have been used. Note that merging this patch is very easy: If there are no other uses of apr_pool_t in the code (one grep) and it compiles, then it will work. *** Second Merge (needed to remove 'delete mCreationMutex' from LLImageDecodeThread::~LLImageDecodeThread). *** Added back #include <apr_pools.h>. Apparently that is needed on libapr version 1.2.8., the version used by Linden Lab, for calls to apr_queue_*. This is a bug in libapr (we also include <apr_queue.h>, that is fixed in (at least) 1.3.7. Note that 1.2.8 is VERY old. Even 1.3.x is old. *** License fixes (GPL -> LGPL). And typo in comments. Addresses merov's comments on the review board. *** Added Merov's compile fixes for windows.
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.cpp151
-rw-r--r--indra/llcommon/llthread.h124
-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, 793 insertions, 615 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 9342a22d46..d5b0a67533 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -32,6 +32,7 @@ set(llcommon_SOURCE_FILES
llallocator_heap_profile.cpp
llapp.cpp
llapr.cpp
+ llaprpool.cpp
llassettype.cpp
llavatarname.cpp
llbase32.cpp
@@ -80,6 +81,7 @@ set(llcommon_SOURCE_FILES
llrand.cpp
llrefcount.cpp
llrun.cpp
+ llscopedvolatileaprpool.h
llsd.cpp
llsdserialize.cpp
llsdserialize_xml.cpp
@@ -121,6 +123,7 @@ 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 39daefd1ad..e5bd2bfa3d 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -136,10 +136,6 @@ 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 d1c44c9403..1e4a51102e 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -29,212 +29,8 @@
#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
@@ -313,15 +109,17 @@ void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle)
//
LLAPRFile::LLAPRFile()
: mFile(NULL),
- mCurrentFilePoolp(NULL)
+ mVolatileFilePoolp(NULL),
+ mRegularFilePoolp(NULL)
{
}
-LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool)
+LLAPRFile::LLAPRFile(std::string const& filename, apr_int32_t flags, S32* sizep, access_t access_type)
: mFile(NULL),
- mCurrentFilePoolp(NULL)
+ mVolatileFilePoolp(NULL),
+ mRegularFilePoolp(NULL)
{
- open(filename, flags, pool);
+ open(filename, flags, access_type, sizep);
}
LLAPRFile::~LLAPRFile()
@@ -338,36 +136,58 @@ apr_status_t LLAPRFile::close()
mFile = NULL ;
}
- if(mCurrentFilePoolp)
+ if (mVolatileFilePoolp)
{
- mCurrentFilePoolp->clearVolatileAPRPool() ;
- mCurrentFilePoolp = NULL ;
+ mVolatileFilePoolp->clearVolatileAPRPool() ;
+ mVolatileFilePoolp = NULL ;
+ }
+
+ if (mRegularFilePoolp)
+ {
+ delete mRegularFilePoolp;
+ mRegularFilePoolp = NULL;
}
return ret ;
}
-apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep)
+apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, access_t access_type, S32* sizep)
{
- apr_status_t s ;
-
- //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));
+ llassert_always(!mFile);
+ llassert_always(!mVolatileFilePoolp && !mRegularFilePoolp);
- if (s != APR_SUCCESS || !mFile)
+ 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)
{
mFile = NULL ;
-
+ close() ;
if (sizep)
{
*sizep = 0;
}
+ return status;
}
- else if (sizep)
+
+ if (sizep)
{
S32 file_size = 0;
apr_off_t offset = 0;
@@ -381,49 +201,7 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLV
*sizep = file_size;
}
- 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 ;
+ return status;
}
// File I/O
@@ -482,45 +260,6 @@ 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)
@@ -553,13 +292,15 @@ 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, LLVolatileAPRPool* pool)
+S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes)
{
- //*****************************************
- apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY);
- //*****************************************
- if (!file_handle)
+ 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)
{
+ ll_apr_warn_status(s);
+ LL_WARNS("APR") << " while attempting to open file \"" << filename << '"' << LL_ENDL;
return 0;
}
@@ -589,14 +330,13 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb
}
}
- //*****************************************
- close(file_handle, pool) ;
- //*****************************************
+ apr_file_close(file_handle);
+
return (S32)bytes_read;
}
//static
-S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
+S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes)
{
apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
if (offset < 0)
@@ -605,11 +345,13 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
offset = 0;
}
- //*****************************************
- apr_file_t* file_handle = open(filename, pool, flags);
- //*****************************************
- if (!file_handle)
+ 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)
{
+ ll_apr_warn_status(s);
+ LL_WARNS("APR") << " while attempting to open file \"" << filename << '"' << LL_ENDL;
return 0;
}
@@ -639,21 +381,18 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
}
}
- //*****************************************
- LLAPRFile::close(file_handle, pool);
- //*****************************************
+ apr_file_close(file_handle);
return (S32)bytes_written;
}
//static
-bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
+bool LLAPRFile::remove(const std::string& filename)
{
apr_status_t s;
- pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
- s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool());
- pool->clearVolatileAPRPool() ;
+ LLScopedVolatileAPRPool pool;
+ s = apr_file_remove(filename.c_str(), pool);
if (s != APR_SUCCESS)
{
@@ -665,13 +404,12 @@ bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
}
//static
-bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool)
+bool LLAPRFile::rename(const std::string& filename, const std::string& newname)
{
apr_status_t s;
- pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
- s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool());
- pool->clearVolatileAPRPool() ;
+ LLScopedVolatileAPRPool pool;
+ s = apr_file_rename(filename.c_str(), newname.c_str(), pool);
if (s != APR_SUCCESS)
{
@@ -683,49 +421,44 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname,
}
//static
-bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
+bool LLAPRFile::isExist(const std::string& filename, apr_int32_t flags)
{
- apr_file_t* apr_file;
+ apr_file_t* file_handle;
apr_status_t s;
- pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
- s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+ LLScopedVolatileAPRPool pool;
+ s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool);
- if (s != APR_SUCCESS || !apr_file)
+ if (s != APR_SUCCESS || !file_handle)
{
- pool->clearVolatileAPRPool() ;
return false;
}
else
{
- apr_file_close(apr_file) ;
- pool->clearVolatileAPRPool() ;
+ apr_file_close(file_handle);
return true;
}
}
//static
-S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool)
+S32 LLAPRFile::size(const std::string& filename)
{
- apr_file_t* apr_file;
+ apr_file_t* file_handle;
apr_finfo_t info;
apr_status_t s;
- pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
- s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+ LLScopedVolatileAPRPool pool;
+ s = apr_file_open(&file_handle, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool);
- if (s != APR_SUCCESS || !apr_file)
+ if (s != APR_SUCCESS || !file_handle)
{
- pool->clearVolatileAPRPool() ;
-
return 0;
}
else
{
- apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file);
+ apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, file_handle);
- apr_file_close(apr_file) ;
- pool->clearVolatileAPRPool() ;
+ apr_file_close(file_handle) ;
if (s == APR_SUCCESS)
{
@@ -739,31 +472,29 @@ S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool)
}
//static
-bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool)
+bool LLAPRFile::makeDir(const std::string& dirname)
{
apr_status_t s;
- pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
- s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool());
- pool->clearVolatileAPRPool() ;
+ LLScopedVolatileAPRPool pool;
+ s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool);
if (s != APR_SUCCESS)
{
ll_apr_warn_status(s);
- LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL;
+ LL_WARNS("APR") << " while attempting to make directory: " << dirname << LL_ENDL;
return false;
}
return true;
}
//static
-bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool)
+bool LLAPRFile::removeDir(const std::string& dirname)
{
apr_status_t s;
- pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
- s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool());
- pool->clearVolatileAPRPool() ;
+ LLScopedVolatileAPRPool pool;
+ s = apr_file_remove(dirname.c_str(), pool);
if (s != APR_SUCCESS)
{
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index af33ce666f..3f846f1314 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -50,71 +50,9 @@
#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;
-
-/**
- * @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 LLAPRPool;
+class LLVolatileAPRPool;
/**
* @class LLScopedLock
@@ -205,15 +143,20 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable
// make this non copyable since a copy closes the file
private:
apr_file_t* mFile ;
- LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool.
+ LLVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use.
+ LLAPRPool* mRegularFilePoolp; // ...or a regular 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(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL);
+ LLAPRFile(std::string const& filename, apr_int32_t flags, S32* sizep = NULL, access_t access_type = short_lived);
~LLAPRFile() ;
-
- 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 open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL);
apr_status_t close() ;
// Returns actual offset, -1 if seek fails
@@ -226,32 +169,24 @@ 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, 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);
+ 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);
// Returns bytes read/written, 0 if read/write fails:
- 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
+ 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
//*******************************************************************************************************************************
};
@@ -267,6 +202,4 @@ 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
new file mode 100644
index 0000000000..6f21b61b65
--- /dev/null
+++ b/indra/llcommon/llaprpool.cpp
@@ -0,0 +1,202 @@
+/**
+ * @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
new file mode 100644
index 0000000000..bf4102c584
--- /dev/null
+++ b/indra/llcommon/llaprpool.h
@@ -0,0 +1,256 @@
+/**
+ * @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 8be9e4f4de..b8a7394852 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -31,17 +31,9 @@
#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();
@@ -55,10 +47,5 @@ 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 ca9cad5d05..171590f3d8 100644
--- a/indra/llcommon/llcommon.h
+++ b/indra/llcommon/llcommon.h
@@ -35,8 +35,6 @@ 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 bb64152407..75048073ca 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -866,6 +866,9 @@ 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 4a42241c4f..15d167c32e 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -296,5 +296,4 @@ 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 d394f179fb..4b5cdbe288 100644
--- a/indra/llcommon/llfixedbuffer.cpp
+++ b/indra/llcommon/llfixedbuffer.cpp
@@ -30,8 +30,7 @@
LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
: LLLineBuffer(),
- mMaxLines(max_lines),
- mMutex(NULL)
+ mMaxLines(max_lines)
{
mTimer.reset();
}
diff --git a/indra/llcommon/llscopedvolatileaprpool.h b/indra/llcommon/llscopedvolatileaprpool.h
new file mode 100644
index 0000000000..dbaf4edcad
--- /dev/null
+++ b/indra/llcommon/llscopedvolatileaprpool.h
@@ -0,0 +1,52 @@
+/**
+ * @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 49d05ef411..4917e3b935 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -63,6 +63,9 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
{
LLThread *threadp = (LLThread *)datap;
+ // Create a thread local data.
+ LLThreadLocalData::create(threadp);
+
// Run the user supplied function
threadp->run();
@@ -75,38 +78,20 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
}
-LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
- mPaused(FALSE),
+LLThread::LLThread(std::string const& name) :
+ mPaused(false),
mName(name),
mAPRThreadp(NULL),
- mStatus(STOPPED)
+ mStatus(STOPPED),
+ mThreadLocalData(NULL)
{
- // 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);
-
- mLocalAPRFilePoolp = NULL ;
+ mRunCondition = new LLCondition;
}
LLThread::~LLThread()
{
shutdown();
-
- if(mLocalAPRFilePoolp)
- {
- delete mLocalAPRFilePoolp ;
- mLocalAPRFilePoolp = NULL ;
- }
}
void LLThread::shutdown()
@@ -143,7 +128,7 @@ void LLThread::shutdown()
if (!isStopped())
{
// This thread just wouldn't stop, even though we gave it time
- llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
+ llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl;
// Put a stake in its heart.
apr_thread_exit(mAPRThreadp, -1);
return;
@@ -153,15 +138,8 @@ void LLThread::shutdown()
delete mRunCondition;
mRunCondition = 0;
-
- if (mIsLocalPool && mAPRPoolp)
- {
- apr_pool_destroy(mAPRPoolp);
- mAPRPoolp = 0;
- }
}
-
void LLThread::start()
{
llassert(isStopped());
@@ -170,7 +148,7 @@ void LLThread::start()
mStatus = RUNNING;
apr_status_t status =
- apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
+ apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool());
if(status == APR_SUCCESS)
{
@@ -195,7 +173,7 @@ void LLThread::pause()
if (!mPaused)
{
// this will cause the thread to stop execution as soon as checkPause() is called
- mPaused = 1; // Does not need to be atomic since this is only set/unset from the main thread
+ mPaused = true; // Does not need to be atomic since this is only set/unset from the main thread
}
}
@@ -203,7 +181,7 @@ void LLThread::unpause()
{
if (mPaused)
{
- mPaused = 0;
+ mPaused = false;
}
wake(); // wake up the thread if necessary
@@ -280,85 +258,76 @@ void LLThread::wakeLocked()
}
}
-//============================================================================
-
-LLMutex::LLMutex(apr_pool_t *poolp) :
- mAPRMutexp(NULL)
-{
- //if (poolp)
- //{
- // mIsLocalPool = FALSE;
- // mAPRPoolp = poolp;
- //}
- //else
- {
- mIsLocalPool = TRUE;
- apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
- }
- apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
-}
+#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;
-LLMutex::~LLMutex()
+//static
+void LLThreadLocalData::init(void)
{
-#if MUTEX_DEBUG
- llassert_always(!isLocked()); // better not be locked!
-#endif
- apr_thread_mutex_destroy(mAPRMutexp);
- mAPRMutexp = NULL;
- if (mIsLocalPool)
+ // Only do this once.
+ if (sThreadLocalDataKey)
{
- apr_pool_destroy(mAPRPoolp);
+ return;
}
-}
+ 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.
-void LLMutex::lock()
-{
- 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;
+ // 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();
#endif
}
-void LLMutex::unlock()
+// This is called once for every thread when the thread is destructed.
+//static
+void LLThreadLocalData::destroy(void* thread_local_data)
{
-#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);
+ delete static_cast<LLThreadLocalData*>(thread_local_data);
}
-bool LLMutex::isLocked()
+//static
+void LLThreadLocalData::create(LLThread* threadp)
{
- apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
- if (APR_STATUS_IS_EBUSY(status))
+ LLThreadLocalData* new_tld = new LLThreadLocalData;
+ if (threadp)
{
- return true;
+ threadp->mThreadLocalData = new_tld;
}
- else
+ apr_status_t status = apr_threadkey_private_set(new_tld, sThreadLocalDataKey);
+ llassert_always(status == APR_SUCCESS);
+}
+
+//static
+LLThreadLocalData& LLThreadLocalData::tldata(void)
+{
+ if (!sThreadLocalDataKey)
{
- apr_thread_mutex_unlock(mAPRMutexp);
- return false;
+ LLThreadLocalData::init();
}
+
+ void* data;
+ apr_status_t status = apr_threadkey_private_get(&data, sThreadLocalDataKey);
+ llassert_always(status == APR_SUCCESS);
+ return *static_cast<LLThreadLocalData*>(data);
}
//============================================================================
-LLCondition::LLCondition(apr_pool_t *poolp) :
- LLMutex(poolp)
+LLCondition::LLCondition(LLAPRPool& parent) : LLMutex(parent)
{
- // base class (LLMutex) has already ensured that mAPRPoolp is set up.
-
- apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
+ apr_thread_cond_create(&mAPRCondp, mPool());
}
@@ -396,7 +365,7 @@ void LLThreadSafeRefCount::initThreadSafeRefCount()
{
if (!sMutex)
{
- sMutex = new LLMutex(0);
+ sMutex = new LLMutex;
}
}
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index f1c6cd75af..757832b8ca 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -29,12 +29,34 @@
#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;
class LLCondition;
+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
{
public:
@@ -45,7 +67,7 @@ public:
QUITTING= 2 // Someone wants this thread to quit
} EThreadStatus;
- LLThread(const std::string& name, apr_pool_t *poolp = NULL);
+ LLThread(std::string const& name);
virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state.
virtual void shutdown(); // stops the thread
@@ -60,7 +82,7 @@ public:
// Called from MAIN THREAD.
void pause();
void unpause();
- bool isPaused() { return isStopped() || mPaused == TRUE; }
+ bool isPaused() { return isStopped() || mPaused; }
// Cause the thread to wake up and check its condition
void wake();
@@ -74,11 +96,11 @@ public:
// this kicks off the apr thread
void start(void);
- apr_pool_t *getAPRPool() { return mAPRPoolp; }
- LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
+ // Return thread-local data for the current thread.
+ static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); }
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);
@@ -88,14 +110,10 @@ protected:
LLCondition* mRunCondition;
apr_thread_t *mAPRThreadp;
- apr_pool_t *mAPRPoolp;
- BOOL mIsLocalPool;
EThreadStatus mStatus;
- //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 ;
+ friend void LLThreadLocalData::create(LLThread* threadp);
+ LLThreadLocalData* mThreadLocalData;
void setQuitting();
@@ -125,30 +143,80 @@ protected:
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
-class LL_COMMON_API LLMutex
+#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:
- 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
-
+ void lock() { apr_thread_mutex_lock(mAPRMutexp); }
+ void unlock() { apr_thread_mutex_unlock(mAPRMutexp); }
+ // 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;
+};
+
+class LL_COMMON_API LLMutex : public LLMutexBase
+{
+public:
+ LLMutex(LLAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent)
+ {
+ apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mPool());
+ }
+ ~LLMutex()
+ {
+ llassert(!isLocked()); // better not be locked!
+ apr_thread_mutex_destroy(mAPRMutexp);
+ mAPRMutexp = NULL;
+ }
+
protected:
- apr_thread_mutex_t *mAPRMutexp;
- apr_pool_t *mAPRPoolp;
- BOOL mIsLocalPool;
-#if MUTEX_DEBUG
- std::map<U32, BOOL> mIsLocked;
+ 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();
#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(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
+ LLCondition(LLAPRPool& parent = LLThread::tldata().mRootPool);
~LLCondition();
void wait(); // blocks
@@ -159,10 +227,10 @@ protected:
apr_thread_cond_t *mAPRCondp;
};
-class LLMutexLock
+class LL_COMMON_API LLMutexLock
{
public:
- LLMutexLock(LLMutex* mutex)
+ LLMutexLock(LLMutexBase* mutex)
{
mMutex = mutex;
mMutex->lock();
@@ -172,7 +240,7 @@ public:
mMutex->unlock();
}
private:
- LLMutex* mMutex;
+ LLMutexBase* mMutex;
};
//============================================================================
diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp
index 8a73e632a9..05d24944f3 100644
--- a/indra/llcommon/llthreadsafequeue.cpp
+++ b/indra/llcommon/llthreadsafequeue.cpp
@@ -34,19 +34,11 @@
//-----------------------------------------------------------------------------
-LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity):
- mOwnsPool(pool == 0),
- mPool(pool),
+LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(unsigned int capacity):
mQueue(0)
{
- 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);
+ mPool.create();
+ apr_status_t status = apr_queue_create(&mQueue, capacity, mPool());
if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue");
}
@@ -59,7 +51,6 @@ 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 58cac38769..43d0b396f2 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(apr_pool_t * pool, unsigned int capacity);
+ LLThreadSafeQueueImplementation(unsigned int capacity);
~LLThreadSafeQueueImplementation();
void pushFront(void * element);
bool tryPushFront(void * element);
@@ -84,8 +84,7 @@ public:
size_t size();
private:
- bool mOwnsPool;
- apr_pool_t * mPool;
+ LLAPRPool mPool; // The pool used for mQueue.
apr_queue_t * mQueue;
};
@@ -99,9 +98,8 @@ class LLThreadSafeQueue
public:
typedef ElementT value_type;
- // 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);
+ // Constructor.
+ LLThreadSafeQueue(unsigned int capacity = 1024);
// Add an element to the front of queue (will block if the queue has
// reached capacity).
@@ -139,8 +137,8 @@ private:
template<typename ElementT>
-LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity):
- mImplementation(pool, capacity)
+LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(unsigned int capacity) :
+ mImplementation(capacity)
{
; // No op.
}
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index 3ac50832fd..6b308bb917 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -37,12 +37,7 @@
LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) :
LLQueuedThread(name, threaded)
{
- mDeleteMutex = new LLMutex(NULL);
-
- if(!mLocalAPRFilePoolp)
- {
- mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
- }
+ mDeleteMutex = new LLMutex;
}
LLWorkerThread::~LLWorkerThread()
@@ -204,7 +199,6 @@ 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 9bff18303e..bef5ef53fe 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -94,7 +94,6 @@ public:
private:
void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
-
};
//============================================================================
@@ -194,7 +193,7 @@ protected:
U32 mRequestPriority; // last priority set
private:
- LLMutex mMutex;
+ LLMutexRootPool mMutex; // Use LLMutexRootPool since this object is created and destructed by multiple threads.
LLAtomicU32 mWorkFlags;
};