davep avatar davep committed d67d0e1 Merge

Merge backout of b782a75c99e6

Comments (0)

Files changed (80)

doc/contributions.txt

 Alejandro Rosenthal
 	VWR-1184
 Aleric Inglewood
-	SNOW-84
 	SNOW-240
-	SNOW-477
 	SNOW-522
 	SNOW-626
-	SNOW-744
 	SNOW-756
 	SNOW-764
-	SNOW-766
 	SNOW-800
 	VWR-10001
 	VWR-10579
 	VWR-24366
 	VWR-24519
 	VWR-24520
+	SNOW-84
+	SNOW-477
+	SNOW-744
+	SNOW-766
 	STORM-163
-	STORM-864
 	STORM-955
 	STORM-960
 Ales Beaumont

indra/llaudio/llaudioengine_fmod.cpp

 		return false;
 	}
 
-	if (!LLAPRFile::isExist(filename, LL_APR_RPB))
+	if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB))
 	{
 		// File not found, abort.
 		return false;

indra/llaudio/llvorbisencode.cpp

 	error_msg.clear();
 
 	//********************************
-	LLAPRFile infile(in_fname, LL_APR_RB);
+	LLAPRFile infile ;
+    infile.open(in_fname,LL_APR_RB);
 	//********************************
 	if (!infile.getFileHandle())
 	{
 
 	S32 data_left = 0;
 
-	LLAPRFile infile(in_fname,LL_APR_RB);
+	LLAPRFile infile ;
+	infile.open(in_fname,LL_APR_RB);
 	if (!infile.getFileHandle())
 	{
 		llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
 		return(LLVORBISENC_SOURCE_OPEN_ERR);
 	}
 
-	LLAPRFile outfile(out_fname, LL_APR_WPB);
+	LLAPRFile outfile ;
+	outfile.open(out_fname,LL_APR_WPB);
 	if (!outfile.getFileHandle())
 	{
 		llwarns << "Couldn't open upload sound file for reading: " << in_fname

indra/llcharacter/llbvhloader.cpp

 	//--------------------------------------------------------------------
 	std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
 
-	LLAPRFile infile(path, LL_APR_R);
+	LLAPRFile infile ;
+	infile.open(path, LL_APR_R);
 	apr_file_t *fp = infile.getFileHandle();
 	if (!fp)
 		return E_ST_NO_XLT_FILE;

indra/llcharacter/llkeyframemotionparam.cpp

 	// open the file
 	//-------------------------------------------------------------------------
 	S32 fileSize = 0;
-	LLAPRFile infile(path, LL_APR_R, &fileSize);
+	LLAPRFile infile ;
+	infile.open(path, LL_APR_R, NULL, &fileSize);
 	apr_file_t* fp = infile.getFileHandle() ;
 	if (!fp || fileSize == 0)
 	{

indra/llcharacter/llstatemachine.cpp

 
 BOOL LLStateDiagram::saveDotFile(const std::string& filename)
 {
-	LLAPRFile outfile(filename, LL_APR_W);
+	LLAPRFile outfile ;
+	outfile.open(filename, LL_APR_W);
 	apr_file_t* dot_file = outfile.getFileHandle() ;
 
 	if (!dot_file)

indra/llcommon/CMakeLists.txt

     llallocator_heap_profile.cpp
     llapp.cpp
     llapr.cpp
-    llaprpool.cpp
     llassettype.cpp
     llavatarname.cpp
     llbase32.cpp
     llrand.cpp
     llrefcount.cpp
     llrun.cpp
-    llscopedvolatileaprpool.h
     llsd.cpp
     llsdserialize.cpp
     llsdserialize_xml.cpp
     llavatarname.h
     llapp.h
     llapr.h
-    llaprpool.h
     llassettype.h
     llassoclist.h
     llavatarconstants.h

indra/llcommon/llapp.cpp

 		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;
 	

indra/llcommon/llapr.cpp

 #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
 //
 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()
 		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;
 		*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
 //
 
 //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)
 }
 
 //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;
 	}
 
 		}
 	}
 	
-	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)
 		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;
 	}
 
 		}
 	}
 
-	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)
 	{
 }
 
 //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)
 	{
 }
 
 //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)
 		{
 }
 
 //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)
 	{

indra/llcommon/llapr.h

 #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
 	// 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
 	
 	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
 //*******************************************************************************************************************************
 };
 
 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

indra/llcommon/llaprpool.cpp

-/**
- * @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)) ;
-}

indra/llcommon/llaprpool.h

-/**
- * @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

indra/llcommon/llcommon.cpp

 #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();
 // 	LLWorkerThread::cleanupClass();
 	LLThreadSafeRefCount::cleanupThreadSafeRefCount();
 	LLTimer::cleanupClass();
+	if (sAprInitialized)
+	{
+		ll_cleanup_apr();
+		sAprInitialized = FALSE;
+	}
 	LLMemory::cleanupClass();
 }

indra/llcommon/llcommon.h

 public:
 	static void initClass();
 	static void cleanupClass();
+private:
+	static BOOL sAprInitialized;
 };
 
 #endif

indra/llcommon/llerror.cpp

 	
 */
 
-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)

indra/llcommon/llerror.h

 		Such computation is done iff the message will be logged.
 	*/
 
+
 #endif // LL_LLERROR_H

indra/llcommon/llfixedbuffer.cpp

 
 LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
 	: LLLineBuffer(),
-	  mMaxLines(max_lines)
+	  mMaxLines(max_lines),
+	  mMutex(NULL)
 {
 	mTimer.reset();
 }

indra/llcommon/llscopedvolatileaprpool.h

-/**
- * @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

indra/llcommon/llthread.cpp

 	local_thread_ID = threadp->mID;
 #endif
 
-	// Create a thread local data.
-	LLThreadLocalData::create(threadp);
-
 	// Run the user supplied function
 	threadp->run();
 
 }
 
 
-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()
 
 	delete mRunCondition;
 	mRunCondition = 0;
+	
+	if (mIsLocalPool && mAPRPoolp)
+	{
+		apr_pool_destroy(mAPRPoolp);
+		mAPRPoolp = 0;
+	}
 }
 
+
 void LLThread::start()
 {
 	llassert(isStopped());
 	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)
 	{	
 	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
 	}	
 }
 
 {
 	if (mPaused)
 	{
-		mPaused = false;
+		mPaused = 0;
 	}
 
 	wake(); // wake up the thread if necessary
 	}
 }
 
-#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()); }
+//============================================================================
+
+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);
+}
+
+
+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);
+	}
+}
 
-// The thread private handle to access the LLThreadLocalData instance.
-apr_threadkey_t* LLThreadLocalData::sThreadLocalDataKey;
 
-//static
-void LLThreadLocalData::init(void)
+void LLMutex::lock()
 {
-	// Only do this once.
-	if (sThreadLocalDataKey)
-	{
-		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.
-
-	// 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();
+	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
 }
 
-// This is called once for every thread when the thread is destructed.
-//static
-void LLThreadLocalData::destroy(void* thread_local_data)
+void LLMutex::unlock()
 {
-	delete static_cast<LLThreadLocalData*>(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);
 }
 
-//static
-void LLThreadLocalData::create(LLThread* threadp)
+bool LLMutex::isLocked()
 {
-	LLThreadLocalData* new_tld = new LLThreadLocalData;
-	if (threadp)
+	apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
+	if (APR_STATUS_IS_EBUSY(status))
 	{
-		threadp->mThreadLocalData = new_tld;
+		return true;
 	}
-	apr_status_t status = apr_threadkey_private_set(new_tld, sThreadLocalDataKey);
-	llassert_always(status == APR_SUCCESS);
-}
-
-//static
-LLThreadLocalData& LLThreadLocalData::tldata(void)
-{
-	if (!sThreadLocalDataKey)
+	else
 	{
-		LLThreadLocalData::init();
+		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);
 }
 
 
 {
 	if (!sMutex)
 	{
-		sMutex = new LLMutex;
+		sMutex = new LLMutex(0);
 	}
 }
 

indra/llcommon/llthread.h

 
 #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;
 #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:
 		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
 	
 	// 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();
 	// 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);
 	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();
 	
 
 #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
+class LL_COMMON_API LLMutex
 {
 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; }
-
+	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:
-	// mAPRMutexp is initialized and uninitialized in the derived class.
-	apr_thread_mutex_t* mAPRMutexp;
-	mutable U32			mCount;
-	mutable U32			mLockingThread;
+	apr_thread_mutex_t *mAPRMutexp;
+	apr_pool_t			*mAPRPoolp;
+	BOOL				mIsLocalPool;
+#if MUTEX_DEBUG
+	std::map<U32, BOOL> mIsLocked;
+#endif
 };
 
-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()
-	{
-		//this assertion erroneously triggers whenever an LLCondition is destroyed
-		//llassert(!isLocked()); // better not be locked!
-		apr_thread_mutex_destroy(mAPRMutexp);
-		mAPRMutexp = NULL;
-	}
-
-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();
-#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
 	apr_thread_cond_t *mAPRCondp;
 };
 
-class LL_COMMON_API LLMutexLock
+class LLMutexLock
 {
 public:
-	LLMutexLock(LLMutexBase* mutex)
+	LLMutexLock(LLMutex* mutex)
 	{
 		mMutex = mutex;
 		mMutex->lock();
 		mMutex->unlock();
 	}
 private:
-	LLMutexBase* mMutex;
+	LLMutex* mMutex;
 };
 
 //============================================================================

indra/llcommon/llthreadsafequeue.cpp

 //-----------------------------------------------------------------------------
 
 
-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");
 }
 
 			" elements;" << "memory will be leaked" << LL_ENDL;
 		apr_queue_term(mQueue);
 	}
+	if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool);
 }
 
 

indra/llcommon/llthreadsafequeue.h

 
 #include <string>
 #include <stdexcept>
-#include "llaprpool.h"
 
 
+struct apr_pool_t; // From apr_pools.h
 class LLThreadSafeQueueImplementation; // See below.
 
 
 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);
 	size_t size();
 	
 private:
-	LLAPRPool mPool;			// The pool used for mQueue.
+	bool mOwnsPool;
+	apr_pool_t * mPool;
 	apr_queue_t * mQueue;
 };
 
 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).
 
 
 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.
 }

indra/llcommon/llworkerthread.cpp

 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()
 	  mWorkerClassName(name),
 	  mRequestHandle(LLWorkerThread::nullHandle()),
 	  mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
+	  mMutex(NULL),
 	  mWorkFlags(0)
 {
 	if (!mWorkerThread)

indra/llcommon/llworkerthread.h

 
 private:
 	void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
+	
 };
 
 //============================================================================
 	U32 mRequestPriority; // last priority set
 
 private:
-	LLMutexRootPool mMutex;		// Use LLMutexRootPool since this object is created and destructed by multiple threads.