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