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