diff options
155 files changed, 7475 insertions, 4383 deletions
@@ -181,4 +181,9 @@ f2412ecd6740803ea9452f1d17fd872e263a0df7 3.0.2-start  1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release  42784bf50fa01974bada2a1af3892ee09c93fcda DRTVWR-83_3.0.2-beta1  42784bf50fa01974bada2a1af3892ee09c93fcda 3.0.2-beta1 +e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e DRTVWR-86_3.0.2-beta2 +e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e 3.0.2-beta2  b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start +6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 DRTVWR-85_3.0.3-beta1 +586907287be581817b2422b5137971b22d54ea48 3.0.4-start +6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 3.0.3-beta1 diff --git a/autobuild.xml b/autobuild.xml index e5c6b83037..347ef419ed 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1206,9 +1206,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>a7c80fd8516df3b879b669b2b220067f</string> +              <string>9cd66e879908f047d9af665b92946ecc</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/232420/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110608.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/239803/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110830.tar.bz2</string>              </map>              <key>name</key>              <string>darwin</string> @@ -1230,9 +1230,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>b9cc0333cc274c9cc40256ab7146b4fc</string> +              <string>ab9393795515cbbe9526bde33b41bf2a</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/232420/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110608.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/239670/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110829.tar.bz2</string>              </map>              <key>name</key>              <string>windows</string> diff --git a/doc/contributions.txt b/doc/contributions.txt index 55a3aaf1f4..5930bab04f 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -65,11 +65,15 @@ Aimee Trescothick  Alejandro Rosenthal  	VWR-1184  Aleric Inglewood +	SNOW-84  	SNOW-240 +	SNOW-477  	SNOW-522  	SNOW-626 +	SNOW-744  	SNOW-756  	SNOW-764 +	SNOW-766  	SNOW-800  	VWR-10001  	VWR-10579 @@ -95,11 +99,8 @@ Aleric Inglewood  	VWR-24366  	VWR-24519  	VWR-24520 -	SNOW-84 -	SNOW-477 -	SNOW-744 -	SNOW-766  	STORM-163 +	STORM-864  	STORM-955  	STORM-960  Ales Beaumont @@ -476,6 +477,7 @@ Identity Euler  Ima Mechanique  	OPEN-50  	OPEN-61 +	OPEN-76  	STORM-1175  Imnotgoing Sideways  Inma Rau @@ -566,6 +568,10 @@ Jonathan Yap  	STORM-1276  	STORM-1462  	STORM-1459 +	STORM-1522 +	STORM-1567 +	STORM-1572 +	STORM-1574  Kadah Coba      STORM-1060  Jondan Lundquist diff --git a/doc/translations.txt b/doc/translations.txt index c9cfc1cdeb..9b7f2d6292 100644 --- a/doc/translations.txt +++ b/doc/translations.txt @@ -1,7 +1,9 @@ -#List of translators who contribute to SL Viewer 2.0+ and SL web translation by language +#List of translators who contribute to SL Viewer 2.0+ by language  	Danish  Flemming Congrejo +	German +Torben Trautman  	French  Valerie Linden  	Polish @@ -21,6 +23,7 @@ Lunita Savira  Minerva Memel  Polo Gufler  Xiki Luik -Perez Linden +Shinya Tandino +Catwise Yoshikawa  	Traditional Chinese  gefeit Dufaux diff --git a/indra/llaudio/llaudioengine_fmod.cpp b/indra/llaudio/llaudioengine_fmod.cpp index a40de9fa68..88dfdb9c24 100644 --- a/indra/llaudio/llaudioengine_fmod.cpp +++ b/indra/llaudio/llaudioengine_fmod.cpp @@ -673,7 +673,7 @@ bool LLAudioBufferFMOD::loadWAV(const std::string& filename)  		return false;  	} -	if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) +	if (!LLAPRFile::isExist(filename, LL_APR_RPB))  	{  		// File not found, abort.  		return false; diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp index 0e0c80a456..44eeea0ca4 100644 --- a/indra/llaudio/llvorbisencode.cpp +++ b/indra/llaudio/llvorbisencode.cpp @@ -82,8 +82,7 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro  	error_msg.clear();  	//******************************** -	LLAPRFile infile ; -    infile.open(in_fname,LL_APR_RB); +	LLAPRFile infile(in_fname, LL_APR_RB);  	//********************************  	if (!infile.getFileHandle())  	{ @@ -233,8 +232,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname  	S32 data_left = 0; -	LLAPRFile infile ; -	infile.open(in_fname,LL_APR_RB); +	LLAPRFile infile(in_fname,LL_APR_RB);  	if (!infile.getFileHandle())  	{  		llwarns << "Couldn't open temporary ogg file for writing: " << in_fname @@ -242,8 +240,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname  		return(LLVORBISENC_SOURCE_OPEN_ERR);  	} -	LLAPRFile outfile ; -	outfile.open(out_fname,LL_APR_WPB); +	LLAPRFile outfile(out_fname, LL_APR_WPB);  	if (!outfile.getFileHandle())  	{  		llwarns << "Couldn't open upload sound file for reading: " << in_fname diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index f3cf950afa..c3c7f03247 100644 --- a/indra/llcharacter/llbvhloader.cpp +++ b/indra/llcharacter/llbvhloader.cpp @@ -219,8 +219,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)  	//--------------------------------------------------------------------  	std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName); -	LLAPRFile infile ; -	infile.open(path, LL_APR_R); +	LLAPRFile infile(path, LL_APR_R);  	apr_file_t *fp = infile.getFileHandle();  	if (!fp)  		return E_ST_NO_XLT_FILE; diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp index 82fe8971f5..c3d5dec875 100644 --- a/indra/llcharacter/llkeyframemotionparam.cpp +++ b/indra/llcharacter/llkeyframemotionparam.cpp @@ -351,8 +351,7 @@ BOOL LLKeyframeMotionParam::loadMotions()  	// open the file  	//-------------------------------------------------------------------------  	S32 fileSize = 0; -	LLAPRFile infile ; -	infile.open(path, LL_APR_R, NULL, &fileSize); +	LLAPRFile infile(path, LL_APR_R, &fileSize);  	apr_file_t* fp = infile.getFileHandle() ;  	if (!fp || fileSize == 0)  	{ diff --git a/indra/llcharacter/llstatemachine.cpp b/indra/llcharacter/llstatemachine.cpp index e0454131a5..dcc4ff5f0e 100644 --- a/indra/llcharacter/llstatemachine.cpp +++ b/indra/llcharacter/llstatemachine.cpp @@ -204,8 +204,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)  BOOL LLStateDiagram::saveDotFile(const std::string& filename)  { -	LLAPRFile outfile ; -	outfile.open(filename, LL_APR_W); +	LLAPRFile outfile(filename, LL_APR_W);  	apr_file_t* dot_file = outfile.getFileHandle() ;  	if (!dot_file) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index c755020a64..60d4cfe6d3 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -31,6 +31,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 @@ -122,6 +124,7 @@ set(llcommon_HEADER_FILES      llavatarname.h      llapp.h      llapr.h +    llaprpool.h      llassettype.h      llassoclist.h      llavatarconstants.h @@ -319,6 +322,7 @@ if (LL_TESTS)    LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}"                            "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/setpython.py") +  LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}")                              LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}") diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index ed192a9975..a8b7106078 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -137,10 +137,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 c35799bbb9..bda9d7c177 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 b3e604f8e8..369f2a7a97 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/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index f576204511..5dc3ea5d7b 100644 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -35,14 +35,15 @@  //static   void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)  { -	static std::map<std::string, void *> instances; +	typedef std::map<std::string, void *> InstancesMap; +	static InstancesMap instances; -	std::string k = info.name(); -	if(instances.find(k) == instances.end()) -	{ -		instances[k] = NULL; -	} - -	return instances[k]; +	// std::map::insert() is just what we want here. You attempt to insert a +	// (key, value) pair. If the specified key doesn't yet exist, it inserts +	// the pair and returns a std::pair of (iterator, true). If the specified +	// key DOES exist, insert() simply returns (iterator, false). One lookup +	// handles both cases. +	return instances.insert(InstancesMap::value_type(info.name(), +													 InstancesMap::mapped_type())) +		.first->second;  } - diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index afb714c71c..5a3990a8df 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -29,6 +29,7 @@  #define LL_LLINSTANCETRACKER_H  #include <map> +#include <typeinfo>  #include "string_table.h"  #include <boost/utility.hpp> @@ -37,10 +38,40 @@  #include <boost/iterator/transform_iterator.hpp>  #include <boost/iterator/indirect_iterator.hpp> +/** + * Base class manages "class-static" data that must actually have singleton + * semantics: one instance per process, rather than one instance per module as + * sometimes happens with data simply declared static. + */  class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable  { -	protected: -		static void * & getInstances(std::type_info const & info); +protected: +	/// Get a process-unique void* pointer slot for the specified type_info +	static void * & getInstances(std::type_info const & info); + +	/// Find or create a STATICDATA instance for the specified TRACKED class. +	/// STATICDATA must be default-constructible. +	template<typename STATICDATA, class TRACKED> +	static STATICDATA& getStatic() +	{ +		void *& instances = getInstances(typeid(TRACKED)); +		if (! instances) +		{ +			instances = new STATICDATA; +		} +		return *static_cast<STATICDATA*>(instances); +	} + +    /// It's not essential to derive your STATICDATA (for use with +    /// getStatic()) from StaticBase; it's just that both known +    /// implementations do. +    struct StaticBase +    { +        StaticBase(): +            sIterationNestDepth(0) +        {} +        S32 sIterationNestDepth; +    };  };  /// This mix-in class adds support for tracking all instances of the specified class parameter T @@ -50,8 +81,15 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable  template<typename T, typename KEY = T*>  class LLInstanceTracker : public LLInstanceTrackerBase  { -	typedef typename std::map<KEY, T*> InstanceMap;  	typedef LLInstanceTracker<T, KEY> MyT; +	typedef typename std::map<KEY, T*> InstanceMap; +	struct StaticData: public StaticBase +	{ +		InstanceMap sMap; +	}; +	static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); } +	static InstanceMap& getMap_() { return getStatic().sMap; } +  public:  	class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>  	{ @@ -61,12 +99,12 @@ public:  		instance_iter(const typename InstanceMap::iterator& it)  		:	mIterator(it)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		~instance_iter()  		{ -			--sIterationNestDepth; +			--getStatic().sIterationNestDepth;  		} @@ -95,18 +133,18 @@ public:  		key_iter(typename InstanceMap::iterator it)  			:	mIterator(it)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		key_iter(const key_iter& other)  			:	mIterator(other.mIterator)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		~key_iter()  		{ -			--sIterationNestDepth; +			--getStatic().sIterationNestDepth;  		} @@ -159,8 +197,8 @@ protected:  	virtual ~LLInstanceTracker()   	{   		// it's unsafe to delete instances of this type while all instances are being iterated over. -		llassert(sIterationNestDepth == 0); -		remove_(); 		 +		llassert_always(getStatic().sIterationNestDepth == 0); +		remove_();		  	}  	virtual void setKey(KEY key) { remove_(); add_(key); }  	virtual const KEY& getKey() const { return mInstanceKey; } @@ -176,31 +214,24 @@ private:  		getMap_().erase(mInstanceKey);  	} -    static InstanceMap& getMap_() -    { -		void * & instances = getInstances(typeid(MyT)); -        if (! instances) -        { -            instances = new InstanceMap; -        } -        return * static_cast<InstanceMap*>(instances); -    } -  private: -  	KEY mInstanceKey; -	static S32 sIterationNestDepth;  }; -template <typename T, typename KEY> S32 LLInstanceTracker<T, KEY>::sIterationNestDepth = 0; -  /// explicit specialization for default case where KEY is T*  /// use a simple std::set<T*>  template<typename T>  class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase  { -	typedef typename std::set<T*> InstanceSet;  	typedef LLInstanceTracker<T, T*> MyT; +	typedef typename std::set<T*> InstanceSet; +	struct StaticData: public StaticBase +	{ +		InstanceSet sSet; +	}; +	static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); } +	static InstanceSet& getSet_() { return getStatic().sSet; } +  public:  	/// for completeness of analogy with the generic implementation @@ -213,18 +244,18 @@ public:  		instance_iter(const typename InstanceSet::iterator& it)  		:	mIterator(it)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		instance_iter(const instance_iter& other)  		:	mIterator(other.mIterator)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		~instance_iter()  		{ -			--sIterationNestDepth; +			--getStatic().sIterationNestDepth;  		}  	private: @@ -250,13 +281,13 @@ public:  protected:  	LLInstanceTracker()  	{ -		// it's safe but unpredictable to create instances of this type while all instances are being iterated over.  I hate unpredictable.  This assert will probably be turned on early in the next development cycle. +		// it's safe but unpredictable to create instances of this type while all instances are being iterated over.  I hate unpredictable.	 This assert will probably be turned on early in the next development cycle.  		getSet_().insert(static_cast<T*>(this));  	}  	virtual ~LLInstanceTracker()  	{  		// it's unsafe to delete instances of this type while all instances are being iterated over. -		llassert(sIterationNestDepth == 0); +		llassert_always(getStatic().sIterationNestDepth == 0);  		getSet_().erase(static_cast<T*>(this));  	} @@ -264,20 +295,6 @@ protected:  	{  		getSet_().insert(static_cast<T*>(this));  	} - -	static InstanceSet& getSet_() -	{ -		void * & instances = getInstances(typeid(MyT)); -		if (! instances) -		{ -			instances = new InstanceSet; -		} -		return * static_cast<InstanceSet *>(instances); -	} - -	static S32 sIterationNestDepth;  }; -template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0; -  #endif diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 21d1c84d69..8c02ad8290 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -26,14 +26,13 @@  #include "linden_common.h" -#include "llmemory.h" -#if MEM_TRACK_MEM +//#if MEM_TRACK_MEM  #include "llthread.h" -#endif +//#endif  #if defined(LL_WINDOWS) -# include <windows.h> +//# include <windows.h>  # include <psapi.h>  #elif defined(LL_DARWIN)  # include <sys/types.h> @@ -43,10 +42,24 @@  # include <unistd.h>  #endif +#include "llmemory.h" + +#include "llsys.h" +#include "llframetimer.h"  //----------------------------------------------------------------------------  //static  char* LLMemory::reserveMem = 0; +U32 LLMemory::sAvailPhysicalMemInKB = U32_MAX ; +U32 LLMemory::sMaxPhysicalMemInKB = 0; +U32 LLMemory::sAllocatedMemInKB = 0; +U32 LLMemory::sAllocatedPageSizeInKB = 0 ; +U32 LLMemory::sMaxHeapSizeInKB = U32_MAX ; +BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE; + +#if __DEBUG_PRIVATE_MEM__ +LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sMemAllocationTracker; +#endif  //static  void LLMemory::initClass() @@ -71,6 +84,148 @@ void LLMemory::freeReserve()  	reserveMem = NULL;  } +//static  +void LLMemory::initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure) +{ +	sMaxHeapSizeInKB = (U32)(max_heap_size_gb * 1024 * 1024) ; +	sEnableMemoryFailurePrevention = prevent_heap_failure ; +} + +//static  +void LLMemory::updateMemoryInfo()  +{ +#if LL_WINDOWS	 +	HANDLE self = GetCurrentProcess(); +	PROCESS_MEMORY_COUNTERS counters; +	 +	if (!GetProcessMemoryInfo(self, &counters, sizeof(counters))) +	{ +		llwarns << "GetProcessMemoryInfo failed" << llendl; +		return ; +	} + +	sAllocatedMemInKB = (U32)(counters.WorkingSetSize / 1024) ; +	sAllocatedPageSizeInKB = (U32)(counters.PagefileUsage / 1024) ; + +	U32 avail_phys, avail_virtual; +	LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ; +	sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); + +	if(sMaxPhysicalMemInKB > sAllocatedMemInKB) +	{ +		sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ; +	} +	else +	{ +		sAvailPhysicalMemInKB = 0 ; +	} +#else +	//not valid for other systems for now. +	sAllocatedMemInKB = (U32)(LLMemory::getCurrentRSS() / 1024) ; +	sMaxPhysicalMemInKB = U32_MAX ; +	sAvailPhysicalMemInKB = U32_MAX ; +#endif + +	return ; +} + +// +//this function is to test if there is enough space with the size in the virtual address space. +//it does not do any real allocation +//if success, it returns the address where the memory chunk can fit in; +//otherwise it returns NULL. +// +//static  +void* LLMemory::tryToAlloc(void* address, U32 size) +{ +#if LL_WINDOWS +	address = VirtualAlloc(address, size, MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS) ; +	if(address) +	{ +		if(!VirtualFree(address, 0, MEM_RELEASE)) +		{ +			llerrs << "error happens when free some memory reservation." << llendl ; +		} +	} +	return address ; +#else +	return (void*)0x01 ; //skip checking +#endif	 +} + +//static  +void LLMemory::logMemoryInfo(BOOL update) +{ +	if(update) +	{ +		updateMemoryInfo() ; +	} + +	llinfos << "Current allocated physical memory(KB): " << sAllocatedMemInKB << llendl ; +	llinfos << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << llendl ; +	llinfos << "Current availabe physical memory(KB): " << sAvailPhysicalMemInKB << llendl ; +	llinfos << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << llendl ; +} + +//return 0: everything is normal; +//return 1: the memory pool is low, but not in danger; +//return -1: the memory pool is in danger, is about to crash. +//static  +S32 LLMemory::isMemoryPoolLow() +{ +	static const U32 LOW_MEMEOY_POOL_THRESHOLD_KB = 64 * 1024 ; //64 MB for emergency use + +	if(!sEnableMemoryFailurePrevention) +	{ +		return 0 ; //no memory failure prevention. +	} + +	if(sAvailPhysicalMemInKB < (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2)) //out of physical memory +	{ +		return -1 ; +	} + +	if(sAllocatedPageSizeInKB + (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2) > sMaxHeapSizeInKB) //out of virtual address space. +	{ +		return -1 ; +	} + +	return (S32)(sAvailPhysicalMemInKB < LOW_MEMEOY_POOL_THRESHOLD_KB ||  +		sAllocatedPageSizeInKB + LOW_MEMEOY_POOL_THRESHOLD_KB > sMaxHeapSizeInKB) ; +} + +//static  +U32 LLMemory::getAvailableMemKB()  +{ +	return sAvailPhysicalMemInKB ; +} + +//static  +U32 LLMemory::getMaxMemKB()  +{ +	return sMaxPhysicalMemInKB ; +} + +//static  +U32 LLMemory::getAllocatedMemKB()  +{ +	return sAllocatedMemInKB ; +} + +void* ll_allocate (size_t size) +{ +	if (size == 0) +	{ +		llwarns << "Null allocation" << llendl; +	} +	void *p = malloc(size); +	if (p == NULL) +	{ +		LLMemory::freeReserve(); +		llerrs << "Out of memory Error" << llendl; +	} +	return p; +}  //---------------------------------------------------------------------------- @@ -237,7 +392,7 @@ U64 LLMemory::getCurrentRSS()  U32 LLMemory::getWorkingSetSize()  { -	return 0 ; +	return 0;  }  #endif @@ -258,7 +413,7 @@ LLMemTracker::LLMemTracker()  	mDrawnIndex = 0 ;  	mPaused = FALSE ; -	mMutexp = new LLMutex(NULL) ; +	mMutexp = new LLMutex() ;  	mStringBuffer = new char*[128] ;  	mStringBuffer[0] = new char[mCapacity * 128] ;  	for(S32 i = 1 ; i < mCapacity ; i++) @@ -376,3 +531,1661 @@ const char* LLMemTracker::getNextLine()  #endif //MEM_TRACK_MEM  //-------------------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- +//minimum slot size and minimal slot size interval +const U32 ATOMIC_MEM_SLOT = 16 ; //bytes + +//minimum block sizes (page size) for small allocation, medium allocation, large allocation  +const U32 MIN_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {2 << 10, 4 << 10, 16 << 10} ; // + +//maximum block sizes for small allocation, medium allocation, large allocation  +const U32 MAX_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {64 << 10, 1 << 20, 4 << 20} ; + +//minimum slot sizes for small allocation, medium allocation, large allocation  +const U32 MIN_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION]  = {ATOMIC_MEM_SLOT, 2 << 10, 512 << 10}; + +//maximum slot sizes for small allocation, medium allocation, large allocation  +const U32 MAX_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION]  = {(2 << 10) - ATOMIC_MEM_SLOT, (512 - 2) << 10, 4 << 20}; + +//size of a block with multiple slots can not exceed CUT_OFF_SIZE +const U32 CUT_OFF_SIZE = (64 << 10) ; //64 KB + +//max number of slots in a block +const U32 MAX_NUM_SLOTS_IN_A_BLOCK = llmin(MIN_BLOCK_SIZES[0] / ATOMIC_MEM_SLOT, ATOMIC_MEM_SLOT * 8) ; + +//------------------------------------------------------------- +//align val to be integer times of ATOMIC_MEM_SLOT +U32 align(U32 val) +{ +	U32 aligned = (val / ATOMIC_MEM_SLOT) * ATOMIC_MEM_SLOT ; +	if(aligned < val) +	{ +		aligned += ATOMIC_MEM_SLOT ; +	} + +	return aligned ; +} + +//------------------------------------------------------------- +//class LLPrivateMemoryPool::LLMemoryBlock +//------------------------------------------------------------- +// +//each memory block could fit for two page sizes: 0.75 * mSlotSize, which starts from the beginning of the memory chunk and grow towards the end of the +//the block; another is mSlotSize, which starts from the end of the block and grows towards the beginning of the block. +// +LLPrivateMemoryPool::LLMemoryBlock::LLMemoryBlock() +{ +	//empty +} +		 +LLPrivateMemoryPool::LLMemoryBlock::~LLMemoryBlock()  +{ +	//empty +} + +//create and initialize a memory block +void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 slot_size) +{ +	mBuffer = buffer ; +	mBufferSize = buffer_size ; +	mSlotSize = slot_size ; +	mTotalSlots = buffer_size / mSlotSize ;	 +	 +	llassert_always(buffer_size / mSlotSize <= MAX_NUM_SLOTS_IN_A_BLOCK) ; //max number is 128 +	 +	mAllocatedSlots = 0 ; +	mDummySize = 0 ; + +	//init the bit map. +	//mark free bits	 +	if(mTotalSlots > 32) //reserve extra space from mBuffer to store bitmap if needed. +	{ +		mDummySize = ATOMIC_MEM_SLOT ;		 +		mTotalSlots -= (mDummySize + mSlotSize - 1) / mSlotSize ; +		mUsageBits = 0 ; + +		S32 usage_bit_len = (mTotalSlots + 31) / 32 ; +		 +		for(S32 i = 0 ; i < usage_bit_len - 1 ; i++) +		{ +			*((U32*)mBuffer + i) = 0 ; +		} +		for(S32 i = usage_bit_len - 1 ; i < mDummySize / sizeof(U32) ; i++) +		{ +			*((U32*)mBuffer + i) = 0xffffffff ; +		} + +		if(mTotalSlots & 31) +		{ +			*((U32*)mBuffer + usage_bit_len - 2) = (0xffffffff << (mTotalSlots & 31)) ; +		}		 +	}	 +	else//no extra bitmap space reserved +	{ +		mUsageBits = 0 ; +		if(mTotalSlots & 31) +		{ +			mUsageBits = (0xffffffff << (mTotalSlots & 31)) ; +		} +	} + +	mSelf = this ; +	mNext = NULL ; +	mPrev = NULL ; + +	llassert_always(mTotalSlots > 0) ; +} + +//mark this block to be free with the memory [mBuffer, mBuffer + mBufferSize). +void LLPrivateMemoryPool::LLMemoryBlock::setBuffer(char* buffer, U32 buffer_size) +{ +	mBuffer = buffer ; +	mBufferSize = buffer_size ; +	mSelf = NULL ; +	mTotalSlots = 0 ; //set the block is free. +} + +//reserve a slot +char* LLPrivateMemoryPool::LLMemoryBlock::allocate()  +{ +	llassert_always(mAllocatedSlots < mTotalSlots) ; +	 +	//find a free slot +	U32* bits = NULL ; +	U32  k = 0 ; +	if(mUsageBits != 0xffffffff) +	{ +		bits = &mUsageBits ; +	} +	else if(mDummySize > 0)//go to extra space +	{		 +		for(S32 i = 0 ; i < mDummySize / sizeof(U32); i++) +		{ +			if(*((U32*)mBuffer + i) != 0xffffffff) +			{ +				bits = (U32*)mBuffer + i ; +				k = i + 1 ; +				break ; +			} +		} +	}	 +	S32 idx = 0 ; +	U32 tmp = *bits ; +	for(; tmp & 1 ; tmp >>= 1, idx++) ; + +	//set the slot reserved +	if(!idx) +	{ +		*bits |= 1 ; +	} +	else +	{ +		*bits |= (1 << idx) ; +	} + +	mAllocatedSlots++ ; +	 +	return mBuffer + mDummySize + (k * 32 + idx) * mSlotSize ; +} + +//free a slot +void  LLPrivateMemoryPool::LLMemoryBlock::freeMem(void* addr)  +{ +	//bit index +	U32 idx = ((U32)addr - (U32)mBuffer - mDummySize) / mSlotSize ; + +	U32* bits = &mUsageBits ; +	if(idx >= 32) +	{ +		bits = (U32*)mBuffer + (idx - 32) / 32 ; +	} + +	//reset the bit +	if(idx & 31) +	{ +		*bits &= ~(1 << (idx & 31)) ; +	} +	else +	{ +		*bits &= ~1 ; +	} + +	mAllocatedSlots-- ; +} + +//for debug use: reset the entire bitmap. +void  LLPrivateMemoryPool::LLMemoryBlock::resetBitMap() +{ +	for(S32 i = 0 ; i < mDummySize / sizeof(U32) ; i++) +	{ +		*((U32*)mBuffer + i) = 0 ; +	} +	mUsageBits = 0 ; +} +//------------------------------------------------------------------- +//class LLMemoryChunk +//-------------------------------------------------------------------- +LLPrivateMemoryPool::LLMemoryChunk::LLMemoryChunk() +{ +	//empty +} + +LLPrivateMemoryPool::LLMemoryChunk::~LLMemoryChunk() +{ +	//empty +} + +//create and init a memory chunk +void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size)  +{ +	mBuffer = buffer ; +	mBufferSize = buffer_size ; +	mAlloatedSize = 0 ; + +	mMetaBuffer = mBuffer + sizeof(LLMemoryChunk) ; + +	mMinBlockSize = min_block_size; //page size +	mMinSlotSize = min_slot_size; +	mMaxSlotSize = max_slot_size ; +	mBlockLevels = mMaxSlotSize / mMinSlotSize ; +	mPartitionLevels = max_block_size / mMinBlockSize + 1 ; + +	S32 max_num_blocks = (buffer_size - sizeof(LLMemoryChunk) - mBlockLevels * sizeof(LLMemoryBlock*) - mPartitionLevels * sizeof(LLMemoryBlock*)) /  +		                 (mMinBlockSize + sizeof(LLMemoryBlock)) ; +	//meta data space +	mBlocks = (LLMemoryBlock*)mMetaBuffer ; //space reserved for all memory blocks. +	mAvailBlockList = (LLMemoryBlock**)((char*)mBlocks + sizeof(LLMemoryBlock) * max_num_blocks) ;  +	mFreeSpaceList = (LLMemoryBlock**)((char*)mAvailBlockList + sizeof(LLMemoryBlock*) * mBlockLevels) ;  +	 +	//data buffer, which can be used for allocation +	mDataBuffer = (char*)mFreeSpaceList + sizeof(LLMemoryBlock*) * mPartitionLevels ; +	 +	//alignmnet +	mDataBuffer = mBuffer + align(mDataBuffer - mBuffer) ; +	 +	//init +	for(U32 i = 0 ; i < mBlockLevels; i++) +	{ +		mAvailBlockList[i] = NULL ; +	} +	for(U32 i = 0 ; i < mPartitionLevels ; i++) +	{ +		mFreeSpaceList[i] = NULL ; +	} + +	//assign the entire chunk to the first block +	mBlocks[0].mPrev = NULL ; +	mBlocks[0].mNext = NULL ; +	mBlocks[0].setBuffer(mDataBuffer, buffer_size - (mDataBuffer - mBuffer)) ; +	addToFreeSpace(&mBlocks[0]) ; + +	mNext = NULL ; +	mPrev = NULL ; +} + +//static  +U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_slot_size,  +													   U32 max_slot_size, U32 min_block_size, U32 max_block_size) +{ +	//for large allocations, reserve some extra memory for meta data to avoid wasting much  +	if(data_buffer_size / min_slot_size < 64) //large allocations +	{ +		U32 overhead = sizeof(LLMemoryChunk) + (data_buffer_size / min_block_size) * sizeof(LLMemoryBlock) + +			sizeof(LLMemoryBlock*) * (max_slot_size / min_slot_size) + sizeof(LLMemoryBlock*) * (max_block_size / min_block_size + 1) ; + +		//round to integer times of min_block_size +		overhead = ((overhead + min_block_size - 1) / min_block_size) * min_block_size ; +		return overhead ; +	} +	else +	{ +		return 0 ; //do not reserve extra overhead if for small allocations +	} +} + +char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) +{ +	if(mMinSlotSize > size) +	{ +		size = mMinSlotSize ; +	} +	if(mAlloatedSize + size  > mBufferSize - (mDataBuffer - mBuffer)) +	{ +		return NULL ; //no enough space in this chunk. +	} + +	char* p = NULL ; +	U32 blk_idx = getBlockLevel(size); + +	LLMemoryBlock* blk = NULL ; + +	//check if there is free block available +	if(mAvailBlockList[blk_idx]) +	{ +		blk = mAvailBlockList[blk_idx] ; +		p = blk->allocate() ; +		 +		if(blk->isFull()) +		{ +			popAvailBlockList(blk_idx) ; +		} +	} + +	//ask for a new block +	if(!p) +	{ +		blk = addBlock(blk_idx) ; +		if(blk) +		{ +			p = blk->allocate() ; + +			if(blk->isFull()) +			{ +				popAvailBlockList(blk_idx) ; +			} +		} +	} + +	//ask for space from larger blocks +	if(!p) +	{ +		for(S32 i = blk_idx + 1 ; i < mBlockLevels; i++) +		{ +			if(mAvailBlockList[i]) +			{ +				blk = mAvailBlockList[i] ; +				p = blk->allocate() ; + +				if(blk->isFull()) +				{ +					popAvailBlockList(i) ; +				} +				break ; +			} +		} +	} + +	if(p && blk) +	{		 +		mAlloatedSize += blk->getSlotSize() ; +	} +	return p ; +} + +void LLPrivateMemoryPool::LLMemoryChunk::freeMem(void* addr) +{	 +	U32 blk_idx = getPageIndex((U32)addr) ; +	LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; +	blk = blk->mSelf ; + +	bool was_full = blk->isFull() ; +	blk->freeMem(addr) ; +	mAlloatedSize -= blk->getSlotSize() ; + +	if(blk->empty()) +	{ +		removeBlock(blk) ; +	} +	else if(was_full) +	{ +		addToAvailBlockList(blk) ; +	}	 +} + +bool LLPrivateMemoryPool::LLMemoryChunk::empty() +{ +	return !mAlloatedSize ; +} + +bool LLPrivateMemoryPool::LLMemoryChunk::containsAddress(const char* addr) const +{ +	return (U32)mBuffer <= (U32)addr && (U32)mBuffer + mBufferSize > (U32)addr ; +} + +//debug use +void LLPrivateMemoryPool::LLMemoryChunk::dump() +{ +#if 0 +	//sanity check +	//for(S32 i = 0 ; i < mBlockLevels ; i++) +	//{ +	//	LLMemoryBlock* blk = mAvailBlockList[i] ; +	//	while(blk) +	//	{ +	//		blk_list.push_back(blk) ; +	//		blk = blk->mNext ; +	//	} +	//} +	for(S32 i = 0 ; i < mPartitionLevels ; i++) +	{ +		LLMemoryBlock* blk = mFreeSpaceList[i] ; +		while(blk) +		{ +			blk_list.push_back(blk) ; +			blk = blk->mNext ; +		} +	} + +	std::sort(blk_list.begin(), blk_list.end(), LLMemoryBlock::CompareAddress()); + +	U32 total_size = blk_list[0]->getBufferSize() ; +	for(U32 i = 1 ; i < blk_list.size(); i++) +	{ +		total_size += blk_list[i]->getBufferSize() ; +		if((U32)blk_list[i]->getBuffer() < (U32)blk_list[i-1]->getBuffer() + blk_list[i-1]->getBufferSize()) +		{ +			llerrs << "buffer corrupted." << llendl ; +		} +	} + +	llassert_always(total_size + mMinBlockSize >= mBufferSize - ((U32)mDataBuffer - (U32)mBuffer)) ; + +	U32 blk_num = (mBufferSize - (mDataBuffer - mBuffer)) / mMinBlockSize ; +	for(U32 i = 0 ; i < blk_num ; ) +	{ +		LLMemoryBlock* blk = &mBlocks[i] ; +		if(blk->mSelf) +		{ +			U32 end = blk->getBufferSize() / mMinBlockSize ; +			for(U32 j = 0 ; j < end ; j++) +			{ +				llassert_always(blk->mSelf == blk || !blk->mSelf) ; +			} +			i += end ; +		} +		else +		{ +			llerrs << "gap happens" << llendl ; +		} +	} +#endif +#if 0 +	llinfos << "---------------------------" << llendl ; +	llinfos << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << llendl ; + +	llinfos << "available blocks ... " << llendl ; +	for(S32 i = 0 ; i < mBlockLevels ; i++) +	{ +		LLMemoryBlock* blk = mAvailBlockList[i] ; +		while(blk) +		{ +			llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ; +			blk = blk->mNext ; +		} +	} + +	llinfos << "free blocks ... " << llendl ; +	for(S32 i = 0 ; i < mPartitionLevels ; i++) +	{ +		LLMemoryBlock* blk = mFreeSpaceList[i] ; +		while(blk) +		{ +			llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ; +			blk = blk->mNext ; +		} +	} +#endif +} + +//compute the size for a block, the size is round to integer times of mMinBlockSize. +U32 LLPrivateMemoryPool::LLMemoryChunk::calcBlockSize(U32 slot_size) +{ +	// +	//Note: we try to make a block to have 32 slots if the size is not over 32 pages +	//32 is the number of bits of an integer in a 32-bit system +	// + +	U32 block_size; +	U32 cut_off_size = llmin(CUT_OFF_SIZE, (U32)(mMinBlockSize << 5)) ; + +	if((slot_size << 5) <= mMinBlockSize)//for small allocations, return one page  +	{ +		block_size = mMinBlockSize ; +	} +	else if(slot_size >= cut_off_size)//for large allocations, return one-slot block +	{ +		block_size = (slot_size / mMinBlockSize) * mMinBlockSize ; +		if(block_size < slot_size) +		{ +			block_size += mMinBlockSize ; +		} +	} +	else //medium allocations +	{ +		if((slot_size << 5) >= cut_off_size) +		{ +			block_size = cut_off_size ; +		} +		else +		{ +			block_size = ((slot_size << 5) / mMinBlockSize) * mMinBlockSize ; +		} +	} + +	llassert_always(block_size >= slot_size) ; + +	return block_size ; +} + +//create a new block in the chunk +LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock(U32 blk_idx) +{	 +	U32 slot_size = mMinSlotSize * (blk_idx + 1) ; +	U32 preferred_block_size = calcBlockSize(slot_size) ;	 +	U16 idx = getPageLevel(preferred_block_size);  +	LLMemoryBlock* blk = NULL ; +	 +	if(mFreeSpaceList[idx])//if there is free slot for blk_idx +	{ +		blk = createNewBlock(mFreeSpaceList[idx], preferred_block_size, slot_size, blk_idx) ; +	} +	else if(mFreeSpaceList[mPartitionLevels - 1]) //search free pool +	{		 +		blk = createNewBlock(mFreeSpaceList[mPartitionLevels - 1], preferred_block_size, slot_size, blk_idx) ; +	} +	else //search for other non-preferred but enough space slot. +	{ +		S32 min_idx = 0 ; +		if(slot_size > mMinBlockSize) +		{ +			min_idx = getPageLevel(slot_size) ; +		} +		for(S32 i = (S32)idx - 1 ; i >= min_idx ; i--) //search the small slots first +		{ +			if(mFreeSpaceList[i]) +			{ +				U32 new_preferred_block_size = mFreeSpaceList[i]->getBufferSize(); +				new_preferred_block_size = (new_preferred_block_size / mMinBlockSize) * mMinBlockSize ; //round to integer times of mMinBlockSize. + +				//create a NEW BLOCK THERE. +				if(new_preferred_block_size >= slot_size) //at least there is space for one slot. +				{ +					 +					blk = createNewBlock(mFreeSpaceList[i], new_preferred_block_size, slot_size, blk_idx) ; +				} +				break ; +			}  +		} + +		if(!blk) +		{ +			for(U16 i = idx + 1 ; i < mPartitionLevels - 1; i++) //search the large slots  +			{ +				if(mFreeSpaceList[i]) +				{ +					//create a NEW BLOCK THERE. +					blk = createNewBlock(mFreeSpaceList[i], preferred_block_size, slot_size, blk_idx) ; +					break ; +				}  +			} +		} +	} + +	return blk ; +} + +//create a new block at the designed location +LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) +{ +	//unlink from the free space +	removeFromFreeSpace(blk) ; + +	//check the rest space +	U32 new_free_blk_size = blk->getBufferSize() - buffer_size ;	 +	if(new_free_blk_size < mMinBlockSize) //can not partition the memory into size smaller than mMinBlockSize +	{ +		new_free_blk_size = 0 ; //discard the last small extra space. +	}			 + +	//add the rest space back to the free list +	if(new_free_blk_size > 0) //blk still has free space +	{ +		LLMemoryBlock* next_blk = blk + (buffer_size / mMinBlockSize) ; +		next_blk->mPrev = NULL ; +		next_blk->mNext = NULL ; +		next_blk->setBuffer(blk->getBuffer() + buffer_size, new_free_blk_size) ; +		addToFreeSpace(next_blk) ; +	} + +	blk->init(blk->getBuffer(), buffer_size, slot_size) ; +	//insert to the available block list... +	mAvailBlockList[blk_idx] = blk ; + +	//mark the address map: all blocks covered by this block space pointing back to this block. +	U32 end = (buffer_size / mMinBlockSize) ; +	for(U32 i = 1 ; i < end ; i++) +	{ +		(blk + i)->mSelf = blk ; +	} + +	return blk ; +} + +//delete a block, release the block to the free pool. +void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk) +{ +	//remove from the available block list +	if(blk->mPrev) +	{ +		blk->mPrev->mNext = blk->mNext ; +	} +	if(blk->mNext) +	{ +		blk->mNext->mPrev = blk->mPrev ; +	} +	U32 blk_idx = getBlockLevel(blk->getSlotSize()); +	if(mAvailBlockList[blk_idx] == blk) +	{ +		mAvailBlockList[blk_idx] = blk->mNext ; +	} + +	blk->mNext = NULL ; +	blk->mPrev = NULL ; +	 +	//mark it free +	blk->setBuffer(blk->getBuffer(), blk->getBufferSize()) ; + +#if 1 +	//merge blk with neighbors if possible +	if(blk->getBuffer() > mDataBuffer) //has the left neighbor +	{ +		if((blk - 1)->mSelf->isFree()) +		{ +			LLMemoryBlock* left_blk = (blk - 1)->mSelf ; +			removeFromFreeSpace((blk - 1)->mSelf); +			left_blk->setBuffer(left_blk->getBuffer(), left_blk->getBufferSize() + blk->getBufferSize()) ; +			blk = left_blk ; +		} +	} +	if(blk->getBuffer() + blk->getBufferSize() <= mBuffer + mBufferSize - mMinBlockSize) //has the right neighbor +	{ +		U32 d = blk->getBufferSize() / mMinBlockSize ; +		if((blk + d)->isFree()) +		{ +			LLMemoryBlock* right_blk = blk + d ; +			removeFromFreeSpace(blk + d) ; +			blk->setBuffer(blk->getBuffer(), blk->getBufferSize() + right_blk->getBufferSize()) ; +		} +	} +#endif +	 +	addToFreeSpace(blk) ; + +	return ; +} + +//the top block in the list is full, pop it out of the list +void LLPrivateMemoryPool::LLMemoryChunk::popAvailBlockList(U32 blk_idx)  +{ +	if(mAvailBlockList[blk_idx]) +	{ +		LLMemoryBlock* next = mAvailBlockList[blk_idx]->mNext ; +		if(next) +		{ +			next->mPrev = NULL ; +		} +		mAvailBlockList[blk_idx]->mPrev = NULL ; +		mAvailBlockList[blk_idx]->mNext = NULL ; +		mAvailBlockList[blk_idx] = next ; +	} +} + +//add the block back to the free pool +void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk)  +{ +	llassert_always(!blk->mPrev) ; +	llassert_always(!blk->mNext) ; + +	U16 free_idx = blk->getBufferSize() / mMinBlockSize - 1; + +	(blk + free_idx)->mSelf = blk ; //mark the end pointing back to the head. +	free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; + +	blk->mNext = mFreeSpaceList[free_idx] ; +	if(mFreeSpaceList[free_idx]) +	{ +		mFreeSpaceList[free_idx]->mPrev = blk ; +	} +	mFreeSpaceList[free_idx] = blk ; +	blk->mPrev = NULL ; +	blk->mSelf = blk ; +	 +	return ; +} + +//remove the space from the free pool +void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk)  +{ +	U16 free_idx = blk->getBufferSize() / mMinBlockSize - 1; +	free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; + +	if(mFreeSpaceList[free_idx] == blk) +	{ +		mFreeSpaceList[free_idx] = blk->mNext ; +	} +	if(blk->mPrev) +	{ +		blk->mPrev->mNext = blk->mNext ; +	} +	if(blk->mNext) +	{ +		blk->mNext->mPrev = blk->mPrev ; +	} +	blk->mNext = NULL ; +	blk->mPrev = NULL ; +	blk->mSelf = NULL ; + +	return ; +} + +void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk)  +{ +	llassert_always(!blk->mPrev) ; +	llassert_always(!blk->mNext) ; + +	U32 blk_idx = getBlockLevel(blk->getSlotSize()); + +	blk->mNext = mAvailBlockList[blk_idx] ; +	if(blk->mNext) +	{ +		blk->mNext->mPrev = blk ; +	} +	blk->mPrev = NULL ; +	mAvailBlockList[blk_idx] = blk ; + +	return ; +} + +U32 LLPrivateMemoryPool::LLMemoryChunk::getPageIndex(U32 addr) +{ +	return (addr - (U32)mDataBuffer) / mMinBlockSize ; +} + +//for mAvailBlockList +U32 LLPrivateMemoryPool::LLMemoryChunk::getBlockLevel(U32 size) +{ +	llassert(size >= mMinSlotSize && size <= mMaxSlotSize) ; + +	//start from 0 +	return (size + mMinSlotSize - 1) / mMinSlotSize - 1 ; +} + +//for mFreeSpaceList +U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) +{ +	//start from 0 +	U16 level = size / mMinBlockSize - 1 ; +	if(level >= mPartitionLevels) +	{ +		level = mPartitionLevels - 1 ; +	} +	return level ; +} + +//------------------------------------------------------------------- +//class LLPrivateMemoryPool +//-------------------------------------------------------------------- +const U32 CHUNK_SIZE = 4 << 20 ; //4 MB +const U32 LARGE_CHUNK_SIZE = 4 * CHUNK_SIZE ; //16 MB +LLPrivateMemoryPool::LLPrivateMemoryPool(S32 type) : +	mMutexp(NULL),	 +	mReservedPoolSize(0), +	mHashFactor(1), +	mType(type) +{ +	const U32 MAX_POOL_SIZE = 256 * 1024 * 1024 ; //256 MB + +	mMaxPoolSize = MAX_POOL_SIZE ; +	if(type == STATIC_THREADED || type == VOLATILE_THREADED) +	{ +		mMutexp = new LLMutex ; +	} + +	for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) +	{ +		mChunkList[i] = NULL ; +	}	 +	 +	mNumOfChunks = 0 ; +} + +LLPrivateMemoryPool::~LLPrivateMemoryPool() +{ +	destroyPool(); +	delete mMutexp ; +} + +char* LLPrivateMemoryPool::allocate(U32 size) +{	 +	if(!size) +	{ +		return NULL ; +	} + +	//if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it +	if(size >= CHUNK_SIZE) +	{ +		return (char*)malloc(size) ; +	} + +	char* p = NULL ; + +	//find the appropriate chunk +	S32 chunk_idx = getChunkIndex(size) ; +	 +	lock() ; + +	LLMemoryChunk* chunk = mChunkList[chunk_idx]; +	while(chunk) +	{ +		if((p = chunk->allocate(size))) +		{ +			break ; +		} +		chunk = chunk->mNext ; +	} +	 +	//fetch new memory chunk +	if(!p) +	{ +		if(mReservedPoolSize + CHUNK_SIZE > mMaxPoolSize) +		{ +			chunk = mChunkList[chunk_idx]; +			while(chunk) +			{ +				if((p = chunk->allocate(size))) +				{ +					break ; +				} +				chunk = chunk->mNext ; +			} +		} + +		chunk = addChunk(chunk_idx) ; +		if(chunk) +		{ +			p = chunk->allocate(size) ; +		} +	} + +	unlock() ; + +	return p ; +} + +void LLPrivateMemoryPool::freeMem(void* addr) +{ +	if(!addr) +	{ +		return ; +	} +	 +	lock() ; +	 +	LLMemoryChunk* chunk = findChunk((char*)addr) ; +	 +	if(!chunk) +	{ +		free(addr) ; //release from heap +	} +	else +	{ +		chunk->freeMem(addr) ; + +		if(chunk->empty()) +		{ +			removeChunk(chunk) ; +		} +	} +	 +	unlock() ; +} + +void LLPrivateMemoryPool::dump() +{ +} + +U32 LLPrivateMemoryPool::getTotalAllocatedSize() +{ +	U32 total_allocated = 0 ; + +	LLMemoryChunk* chunk ; +	for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) +	{ +		chunk = mChunkList[i]; +		while(chunk) +		{ +			total_allocated += chunk->getAllocatedSize() ; +			chunk = chunk->mNext ; +		} +	} + +	return total_allocated ; +} + +void LLPrivateMemoryPool::lock() +{ +	if(mMutexp) +	{ +		mMutexp->lock() ; +	} +} + +void LLPrivateMemoryPool::unlock() +{ +	if(mMutexp) +	{ +		mMutexp->unlock() ; +	} +} + +S32  LLPrivateMemoryPool::getChunkIndex(U32 size)  +{ +	S32 i ; +	for(i = 0 ; size > MAX_SLOT_SIZES[i]; i++); +	 +	llassert_always(i < SUPER_ALLOCATION); + +	return i ; +} + +//destroy the entire pool +void  LLPrivateMemoryPool::destroyPool() +{ +	lock() ; + +	if(mNumOfChunks > 0) +	{ +		llwarns << "There is some memory not freed when destroy the memory pool!" << llendl ; +	} + +	mNumOfChunks = 0 ; +	mChunkHashList.clear() ; +	mHashFactor = 1 ; +	for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) +	{ +		mChunkList[i] = NULL ; +	} + +	unlock() ; +} + +void  LLPrivateMemoryPool::checkSize(U32 asked_size) +{ +	if(mReservedPoolSize + asked_size > mMaxPoolSize) +	{ +		llinfos << "Max pool size: " << mMaxPoolSize << llendl ; +		llinfos << "Total reserved size: " << mReservedPoolSize + asked_size << llendl ; +		llinfos << "Total_allocated Size: " << getTotalAllocatedSize() << llendl ; + +		llerrs << "The pool is overflowing..." << llendl ; +	} +} + +LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_index) +{ +	U32 preferred_size ; +	U32 overhead ; +	if(chunk_index < LARGE_ALLOCATION) +	{ +		preferred_size = CHUNK_SIZE ; //4MB +		overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_SLOT_SIZES[chunk_index], +			MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ; +	} +	else +	{ +		preferred_size = LARGE_CHUNK_SIZE ; //16MB +		overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_SLOT_SIZES[chunk_index],  +			MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ; +	} + +	checkSize(preferred_size + overhead) ; +	mReservedPoolSize += preferred_size + overhead ; + +	char* buffer = (char*)malloc(preferred_size + overhead) ; +	if(!buffer) +	{ +		return NULL ; +	} +	 +	LLMemoryChunk* chunk = new (buffer) LLMemoryChunk() ; +	chunk->init(buffer, preferred_size + overhead, MIN_SLOT_SIZES[chunk_index], +		MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ; + +	//add to the tail of the linked list +	{ +		if(!mChunkList[chunk_index]) +		{ +			mChunkList[chunk_index] = chunk ; +		} +		else +		{ +			LLMemoryChunk* cur = mChunkList[chunk_index] ; +			while(cur->mNext) +			{ +				cur = cur->mNext ; +			} +			cur->mNext = chunk ; +			chunk->mPrev = cur ; +		} +	} + +	//insert into the hash table +	addToHashTable(chunk) ; +	 +	mNumOfChunks++; + +	return chunk ; +} + +void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk)  +{ +	if(!chunk) +	{ +		return ; +	} + +	//remove from the linked list +	for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) +	{ +		if(mChunkList[i] == chunk) +		{ +			mChunkList[i] = chunk->mNext ; +		} +	} + +	if(chunk->mPrev) +	{ +		chunk->mPrev->mNext = chunk->mNext ; +	} +	if(chunk->mNext) +	{ +		chunk->mNext->mPrev = chunk->mPrev ; +	} + +	//remove from the hash table +	removeFromHashTable(chunk) ; +	 +	mNumOfChunks--; +	mReservedPoolSize -= chunk->getBufferSize() ; +	 +	//release memory +	free(chunk->getBuffer()) ; +} + +U16 LLPrivateMemoryPool::findHashKey(const char* addr) +{ +	return (((U32)addr) / CHUNK_SIZE) % mHashFactor ; +} + +LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* addr) +{ +	U16 key = findHashKey(addr) ;	 +	if(mChunkHashList.size() <= key) +	{ +		return NULL ; +	} + +	return mChunkHashList[key].findChunk(addr) ;	 +} + +void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk)  +{ +	static const U16 HASH_FACTORS[] = {41, 83, 193, 317, 419, 523, 0xFFFF};  +	 +	U16 i ; +	if(mChunkHashList.empty()) +	{ +		mHashFactor = HASH_FACTORS[0] ; +		rehash() ;		 +	} + +	U16 start_key = findHashKey(chunk->getBuffer()) ; +	U16 end_key = findHashKey(chunk->getBuffer() + chunk->getBufferSize() - 1) ; +	bool need_rehash = false ; +	 +	if(mChunkHashList[start_key].hasElement(chunk)) +	{ +		return; //already inserted. +	} +	need_rehash = mChunkHashList[start_key].add(chunk) ; +	 +	if(start_key == end_key && !need_rehash) +	{ +		return ; //done +	} + +	if(!need_rehash) +	{ +		need_rehash = mChunkHashList[end_key].add(chunk) ; +	} + +	if(!need_rehash) +	{ +		if(end_key < start_key) +		{ +			need_rehash = fillHashTable(start_key + 1, mHashFactor, chunk) ; +			if(!need_rehash) +			{ +				need_rehash = fillHashTable(0, end_key, chunk) ; +			} +		} +		else +		{ +			need_rehash = fillHashTable(start_key + 1, end_key, chunk) ; +		} +	} +	 +	if(need_rehash) +	{ +		i = 0 ; +		while(HASH_FACTORS[i] <= mHashFactor) i++; + +		mHashFactor = HASH_FACTORS[i] ; +		llassert_always(mHashFactor != 0xFFFF) ;//stop point to prevent endlessly recursive calls + +		rehash() ; +	} +} + +void LLPrivateMemoryPool::removeFromHashTable(LLMemoryChunk* chunk)  +{ +	U16 start_key = findHashKey(chunk->getBuffer()) ; +	U16 end_key = findHashKey(chunk->getBuffer() + chunk->getBufferSize() - 1) ; +	 +	mChunkHashList[start_key].remove(chunk) ; +	if(start_key == end_key) +	{ +		return ; //done +	} + +	mChunkHashList[end_key].remove(chunk) ; +	 +	if(end_key < start_key) +	{ +		for(U16 i = start_key + 1 ; i < mHashFactor; i++) +		{ +			mChunkHashList[i].remove(chunk) ; +		} +		for(U16 i = 0 ; i < end_key; i++) +		{ +			mChunkHashList[i].remove(chunk) ; +		} +	} +	else +	{ +		for(U16 i = start_key + 1 ; i < end_key; i++) +		{ +			mChunkHashList[i].remove(chunk) ; +		} +	} +} + +void LLPrivateMemoryPool::rehash() +{ +	llinfos << "new hash factor: " << mHashFactor << llendl ; + +	mChunkHashList.clear() ; +	mChunkHashList.resize(mHashFactor) ; + +	LLMemoryChunk* chunk ; +	for(U16 i = 0 ; i < SUPER_ALLOCATION ; i++) +	{ +		chunk = mChunkList[i] ;  +		while(chunk) +		{ +			addToHashTable(chunk) ; +			chunk = chunk->mNext ; +		} +	} +} + +bool LLPrivateMemoryPool::fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) +{ +	for(U16 i = start; i < end; i++) +	{ +		if(mChunkHashList[i].add(chunk)) +		{			 +			return true ; +		}		 +	} + +	return false ; +} + +//-------------------------------------------------------------------- +// class LLChunkHashElement +//-------------------------------------------------------------------- +LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::LLChunkHashElement::findChunk(const char* addr) +{ +	if(mFirst && mFirst->containsAddress(addr)) +	{ +		return mFirst ; +	} +	else if(mSecond && mSecond->containsAddress(addr)) +	{ +		return mSecond ; +	} + +	return NULL ; +} + +//return false if successfully inserted to the hash slot. +bool LLPrivateMemoryPool::LLChunkHashElement::add(LLPrivateMemoryPool::LLMemoryChunk* chunk) +{ +	llassert_always(!hasElement(chunk)) ; + +	if(!mFirst) +	{ +		mFirst = chunk ; +	} +	else if(!mSecond) +	{ +		mSecond = chunk ; +	} +	else +	{ +		return true ; //failed +	} + +	return false ; +} + +void LLPrivateMemoryPool::LLChunkHashElement::remove(LLPrivateMemoryPool::LLMemoryChunk* chunk) +{ +	if(mFirst == chunk) +	{ +		mFirst = NULL ; +	} +	else if(mSecond ==chunk) +	{ +		mSecond = NULL ; +	} +	else +	{ +		llerrs << "This slot does not contain this chunk!" << llendl ; +	} +} + +//-------------------------------------------------------------------- +//class LLPrivateMemoryPoolManager +//-------------------------------------------------------------------- +LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::sInstance = NULL ; + +LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager(BOOL enabled)  +{ +	mPoolList.resize(LLPrivateMemoryPool::MAX_TYPES) ; + +	for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) +	{ +		mPoolList[i] = NULL ; +	} + +	mPrivatePoolEnabled = enabled ; +} + +LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager()  +{ + +#if __DEBUG_PRIVATE_MEM__ +	if(!sMemAllocationTracker.empty()) +	{ +		llwarns << "there is potential memory leaking here. The list of not freed memory blocks are from: " <<llendl ; + +		S32 k = 0 ; +		for(mem_allocation_info_t::iterator iter = sMemAllocationTracker.begin() ; iter != sMemAllocationTracker.end() ; ++iter) +		{ +			llinfos << k++ << ", " << iter->second << llendl ; +		} +		sMemAllocationTracker.clear() ; +	} +#endif + +#if 0 +	//all private pools should be released by their owners before reaching here. +	for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) +	{ +		llassert_always(!mPoolList[i]) ; +	} +	mPoolList.clear() ; + +#else +	//forcefully release all memory +	for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) +	{ +		if(mPoolList[i]) +		{ +			delete mPoolList[i] ; +			mPoolList[i] = NULL ; +		} +	} +	mPoolList.clear() ; +#endif +} + +//static  +void LLPrivateMemoryPoolManager::initClass(BOOL enabled)  +{ +	llassert_always(!sInstance) ; + +	sInstance = new LLPrivateMemoryPoolManager(enabled) ; +} + +//static  +LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::getInstance()  +{ +	//if(!sInstance) +	//{ +	//	sInstance = new LLPrivateMemoryPoolManager(FALSE) ; +	//} +	return sInstance ; +} +	 +//static  +void LLPrivateMemoryPoolManager::destroyClass()  +{ +	if(sInstance) +	{ +		delete sInstance ; +		sInstance = NULL ; +	} +} + +LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(S32 type)  +{ +	if(!mPrivatePoolEnabled) +	{ +		return NULL ; +	} + +	if(!mPoolList[type]) +	{ +		mPoolList[type] = new LLPrivateMemoryPool(type) ; +	} + +	return mPoolList[type] ; +} + +void LLPrivateMemoryPoolManager::deletePool(LLPrivateMemoryPool* pool)  +{ +	if(pool && pool->isEmpty()) +	{ +		mPoolList[pool->getType()] = NULL ; +		delete pool; +	} +} + +//debug +void LLPrivateMemoryPoolManager::updateStatistics() +{ +	mTotalReservedSize = 0 ; +	mTotalAllocatedSize = 0 ; + +	for(U32 i = 0; i < mPoolList.size(); i++) +	{ +		if(mPoolList[i]) +		{ +			mTotalReservedSize += mPoolList[i]->getTotalReservedSize() ; +			mTotalAllocatedSize += mPoolList[i]->getTotalAllocatedSize() ; +		} +	} +} + +#if __DEBUG_PRIVATE_MEM__ +//static  +char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line)  +{ +	char* p ; + +	if(!poolp) +	{ +		p = (char*)malloc(size) ; +	} +	else +	{ +		p = poolp->allocate(size) ; +	} +	 +	if(p) +	{ +		char num[16] ; +		sprintf(num, " line: %d ", line) ; +		std::string str(function) ; +		str += num;  + +		sMemAllocationTracker[p] = str ; +	} + +	return p ; +}	 +#else +//static  +char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size)  +{ +	if(poolp) +	{ +		return poolp->allocate(size) ;		 +	} +	else +	{ +		return (char*)malloc(size) ; +	} +} +#endif + +//static  +void  LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr)  +{ +	if(!addr) +	{ +		return ; +	} + +#if __DEBUG_PRIVATE_MEM__ +	sMemAllocationTracker.erase((char*)addr) ; +#endif + +	if(poolp) +	{ +		poolp->freeMem(addr) ; +	} +	else +	{ +		free(addr) ; +	}	 +} + +//-------------------------------------------------------------------- +//class LLPrivateMemoryPoolTester +//-------------------------------------------------------------------- +#if 0 +LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::sInstance = NULL ; +LLPrivateMemoryPool* LLPrivateMemoryPoolTester::sPool = NULL ; +LLPrivateMemoryPoolTester::LLPrivateMemoryPoolTester() +{	 +} +	 +LLPrivateMemoryPoolTester::~LLPrivateMemoryPoolTester()  +{	 +} + +//static  +LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::getInstance()  +{ +	if(!sInstance) +	{ +		sInstance = ::new LLPrivateMemoryPoolTester() ; +	} +	return sInstance ; +} + +//static  +void LLPrivateMemoryPoolTester::destroy() +{ +	if(sInstance) +	{ +		::delete sInstance ; +		sInstance = NULL ; +	} + +	if(sPool) +	{ +		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; +		sPool = NULL ; +	} +} + +void LLPrivateMemoryPoolTester::run(S32 type)  +{ +	if(sPool) +	{ +		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; +	} +	sPool = LLPrivateMemoryPoolManager::getInstance()->newPool(type) ; + +	//run the test +	correctnessTest() ; +	performanceTest() ; +	//fragmentationtest() ; + +	//release pool. +	LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; +	sPool = NULL ; +} + +void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 times,  +									 bool random_deletion, bool output_statistics) +{ +	U32 levels = (max_size - min_size) / stride + 1 ; +	char*** p ; +	U32 i, j ; +	U32 total_allocated_size = 0 ; + +	//allocate space for p ; +	if(!(p = ::new char**[times]) || !(*p = ::new char*[times * levels])) +	{ +		llerrs << "memory initialization for p failed" << llendl ; +	} + +	//init +	for(i = 0 ; i < times; i++) +	{ +		p[i] = *p + i * levels ; +		for(j = 0 ; j < levels; j++) +		{ +			p[i][j] = NULL ; +		} +	} + +	//allocation +	U32 size ; +	for(i = 0 ; i < times ; i++) +	{ +		for(j = 0 ; j < levels; j++)  +		{ +			size = min_size + j * stride ; +			p[i][j] = ALLOCATE_MEM(sPool, size) ; + +			total_allocated_size+= size ; + +			*(U32*)p[i][j] = i ; +			*((U32*)p[i][j] + 1) = j ; +			//p[i][j][size - 1] = '\0' ; //access the last element to verify the success of the allocation. + +			//randomly release memory +			if(random_deletion) +			{ +				S32 k = rand() % levels ; + +				if(p[i][k]) +				{ +					llassert_always(*(U32*)p[i][k] == i && *((U32*)p[i][k] + 1) == k) ; +					FREE_MEM(sPool, p[i][k]) ; +					total_allocated_size -= min_size + k * stride ; +					p[i][k] = NULL ; +				} +			} +		} +	} + +	//output pool allocation statistics +	if(output_statistics) +	{ +	} + +	//release all memory allocations +	for(i = 0 ; i < times; i++) +	{ +		for(j = 0 ; j < levels; j++) +		{ +			if(p[i][j]) +			{ +				llassert_always(*(U32*)p[i][j] == i && *((U32*)p[i][j] + 1) == j) ; +				FREE_MEM(sPool, p[i][j]) ; +				total_allocated_size -= min_size + j * stride ; +				p[i][j] = NULL ; +			} +		} +	} + +	::delete[] *p ; +	::delete[] p ; +} + +void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) +{ +	LLTimer timer ; + +	llinfos << " -**********************- " << llendl ; +	llinfos << "test size: " << size << " test times: " << times << llendl ; + +	timer.reset() ; +	char** p = new char*[times] ; +		 +	//using the customized memory pool +	//allocation +	for(U32 i = 0 ; i < times; i++) +	{ +		p[i] = ALLOCATE_MEM(sPool, size) ; +		if(!p[i]) +		{ +			llerrs << "allocation failed" << llendl ; +		} +	} +	//de-allocation +	for(U32 i = 0 ; i < times; i++) +	{ +		FREE_MEM(sPool, p[i]) ; +		p[i] = NULL ; +	} +	llinfos << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << llendl ; + +	timer.reset() ; + +	//using the standard allocator/de-allocator: +	//allocation +	for(U32 i = 0 ; i < times; i++) +	{ +		p[i] = ::new char[size] ; +		if(!p[i]) +		{ +			llerrs << "allocation failed" << llendl ; +		} +	} +	//de-allocation +	for(U32 i = 0 ; i < times; i++) +	{ +		::delete[] p[i] ; +		p[i] = NULL ; +	} +	llinfos << "time spent using standard allocator/de-allocator: " << timer.getElapsedTimeF32() << llendl ; + +	delete[] p; +} + +void LLPrivateMemoryPoolTester::correctnessTest()  +{ +	//try many different sized allocation, and all kinds of edge cases, access the allocated memory  +	//to see if allocation is right. +	 +	//edge case +	char* p = ALLOCATE_MEM(sPool, 0) ; +	FREE_MEM(sPool, p) ; + +	//small sized +	// [8 bytes, 2KB), each asks for 256 allocations and deallocations +	test(8, 2040, 8, 256, true, true) ; +	 +	//medium sized +	//[2KB, 512KB), each asks for 16 allocations and deallocations +	test(2048, 512 * 1024 - 2048, 2048, 16, true, true) ; + +	//large sized +	//[512KB, 4MB], each asks for 8 allocations and deallocations +	test(512 * 1024, 4 * 1024 * 1024, 64 * 1024, 6, true, true) ; +} + +void LLPrivateMemoryPoolTester::performanceTest()  +{ +	U32 test_size[3] = {768, 3* 1024, 3* 1024 * 1024}; +	 +	//small sized +	testAndTime(test_size[0], 8) ; +	 +	//medium sized +	testAndTime(test_size[1], 8) ; + +	//large sized +	testAndTime(test_size[2], 8) ; +} + +void LLPrivateMemoryPoolTester::fragmentationtest()  +{ +	//for internal fragmentation statistics: +	//every time when asking for a new chunk during correctness test, and performance test, +	//print out the chunk usage statistices. +} +#endif +//-------------------------------------------------------------------- diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 3bd1403576..db753f0d8b 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -27,7 +27,6 @@  #define LLMEMORY_H  #include "llmemtype.h" -  #if LL_DEBUG  inline void* ll_aligned_malloc( size_t size, int align )  { @@ -105,6 +104,10 @@ inline void ll_aligned_free_32(void *p)  #define ll_aligned_free_32 free  #endif // LL_DEBUG +#ifndef __DEBUG_PRIVATE_MEM__ +#define __DEBUG_PRIVATE_MEM__  0 +#endif +  class LL_COMMON_API LLMemory  {  public: @@ -115,8 +118,24 @@ public:  	// Return value is zero if not known.  	static U64 getCurrentRSS();  	static U32 getWorkingSetSize(); +	static void* tryToAlloc(void* address, U32 size); +	static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure); +	static void updateMemoryInfo() ; +	static void logMemoryInfo(BOOL update = FALSE); +	static S32  isMemoryPoolLow(); + +	static U32 getAvailableMemKB() ; +	static U32 getMaxMemKB() ; +	static U32 getAllocatedMemKB() ;  private:  	static char* reserveMem; +	static U32 sAvailPhysicalMemInKB ; +	static U32 sMaxPhysicalMemInKB ; +	static U32 sAllocatedMemInKB; +	static U32 sAllocatedPageSizeInKB ; + +	static U32 sMaxHeapSizeInKB; +	static BOOL sEnableMemoryFailurePrevention;  };  //---------------------------------------------------------------------------- @@ -163,6 +182,326 @@ private:  //---------------------------------------------------------------------------- + +// +//class LLPrivateMemoryPool defines a private memory pool for an application to use, so the application does not +//need to access the heap directly fro each memory allocation. Throught this, the allocation speed is faster,  +//and reduces virtaul address space gragmentation problem. +//Note: this class is thread-safe by passing true to the constructor function. However, you do not need to do this unless +//you are sure the memory allocation and de-allocation will happen in different threads. To make the pool thread safe +//increases allocation and deallocation cost. +// +class LL_COMMON_API LLPrivateMemoryPool +{ +	friend class LLPrivateMemoryPoolManager ; + +public: +	class LL_COMMON_API LLMemoryBlock //each block is devided into slots uniformly +	{ +	public:  +		LLMemoryBlock() ; +		~LLMemoryBlock() ; + +		void init(char* buffer, U32 buffer_size, U32 slot_size) ; +		void setBuffer(char* buffer, U32 buffer_size) ; + +		char* allocate() ; +		void  freeMem(void* addr) ; + +		bool empty() {return !mAllocatedSlots;} +		bool isFull() {return mAllocatedSlots == mTotalSlots;} +		bool isFree() {return !mTotalSlots;} + +		U32  getSlotSize()const {return mSlotSize;} +		U32  getTotalSlots()const {return mTotalSlots;} +		U32  getBufferSize()const {return mBufferSize;} +		char* getBuffer() const {return mBuffer;} + +		//debug use +		void resetBitMap() ; +	private: +		char* mBuffer; +		U32   mSlotSize ; //when the block is not initialized, it is the buffer size. +		U32   mBufferSize ; +		U32   mUsageBits ; +		U8    mTotalSlots ; +		U8    mAllocatedSlots ; +		U8    mDummySize ; //size of extra bytes reserved for mUsageBits. + +	public: +		LLMemoryBlock* mPrev ; +		LLMemoryBlock* mNext ; +		LLMemoryBlock* mSelf ; + +		struct CompareAddress +		{ +			bool operator()(const LLMemoryBlock* const& lhs, const LLMemoryBlock* const& rhs) +			{ +				return (U32)lhs->getBuffer() < (U32)rhs->getBuffer(); +			} +		}; +	}; + +	class LL_COMMON_API LLMemoryChunk //is divided into memory blocks. +	{ +	public: +		LLMemoryChunk() ; +		~LLMemoryChunk() ; + +		void init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) ; +		void setBuffer(char* buffer, U32 buffer_size) ; + +		bool empty() ; +		 +		char* allocate(U32 size) ; +		void  freeMem(void* addr) ; + +		char* getBuffer() const {return mBuffer;} +		U32 getBufferSize() const {return mBufferSize;} +		U32 getAllocatedSize() const {return mAlloatedSize;} + +		bool containsAddress(const char* addr) const; + +		static U32 getMaxOverhead(U32 data_buffer_size, U32 min_slot_size,  +													   U32 max_slot_size, U32 min_block_size, U32 max_block_size) ; +	 +		void dump() ; + +	private: +		U32 getPageIndex(U32 addr) ; +		U32 getBlockLevel(U32 size) ; +		U16 getPageLevel(U32 size) ; +		LLMemoryBlock* addBlock(U32 blk_idx) ; +		void popAvailBlockList(U32 blk_idx) ; +		void addToFreeSpace(LLMemoryBlock* blk) ; +		void removeFromFreeSpace(LLMemoryBlock* blk) ; +		void removeBlock(LLMemoryBlock* blk) ; +		void addToAvailBlockList(LLMemoryBlock* blk) ; +		U32  calcBlockSize(U32 slot_size); +		LLMemoryBlock* createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) ; + +	private: +		LLMemoryBlock** mAvailBlockList ;//256 by mMinSlotSize +		LLMemoryBlock** mFreeSpaceList; +		LLMemoryBlock*  mBlocks ; //index of blocks by address. +		 +		char* mBuffer ; +		U32   mBufferSize ; +		char* mDataBuffer ; +		char* mMetaBuffer ; +		U32   mMinBlockSize ; +		U32   mMinSlotSize ; +		U32   mMaxSlotSize ; +		U32   mAlloatedSize ; +		U16   mBlockLevels; +		U16   mPartitionLevels; + +	public: +		//form a linked list +		LLMemoryChunk* mNext ; +		LLMemoryChunk* mPrev ; +	} ; + +private: +	LLPrivateMemoryPool(S32 type) ; +	~LLPrivateMemoryPool() ; + +	char *allocate(U32 size) ; +	void  freeMem(void* addr) ; +	 +	void  dump() ; +	U32   getTotalAllocatedSize() ; +	U32   getTotalReservedSize() {return mReservedPoolSize;} +	S32   getType() const {return mType; } +	bool  isEmpty() const {return !mNumOfChunks; } + +private: +	void lock() ; +	void unlock() ;	 +	S32 getChunkIndex(U32 size) ; +	LLMemoryChunk*  addChunk(S32 chunk_index) ; +	void checkSize(U32 asked_size) ; +	void removeChunk(LLMemoryChunk* chunk) ; +	U16  findHashKey(const char* addr); +	void addToHashTable(LLMemoryChunk* chunk) ; +	void removeFromHashTable(LLMemoryChunk* chunk) ; +	void rehash() ; +	bool fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) ; +	LLMemoryChunk* findChunk(const char* addr) ; + +	void destroyPool() ; + +public: +	enum +	{ +		SMALL_ALLOCATION = 0, //from 8 bytes to 2KB(exclusive), page size 2KB, max chunk size is 4MB. +		MEDIUM_ALLOCATION,    //from 2KB to 512KB(exclusive), page size 32KB, max chunk size 4MB +		LARGE_ALLOCATION,     //from 512KB to 4MB(inclusive), page size 64KB, max chunk size 16MB +		SUPER_ALLOCATION      //allocation larger than 4MB. +	}; + +	enum +	{ +		STATIC = 0 ,       //static pool(each alllocation stays for a long time) without threading support +		VOLATILE,          //Volatile pool(each allocation stays for a very short time) without threading support +		STATIC_THREADED,   //static pool with threading support +		VOLATILE_THREADED, //volatile pool with threading support +		MAX_TYPES +	}; //pool types + +private: +	LLMutex* mMutexp ; +	U32  mMaxPoolSize; +	U32  mReservedPoolSize ;	 + +	LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address	 +	U16 mNumOfChunks ; +	U16 mHashFactor ; + +	S32 mType ; + +	class LLChunkHashElement +	{ +	public: +		LLChunkHashElement() {mFirst = NULL ; mSecond = NULL ;} + +		bool add(LLMemoryChunk* chunk) ; +		void remove(LLMemoryChunk* chunk) ; +		LLMemoryChunk* findChunk(const char* addr) ; + +		bool empty() {return !mFirst && !mSecond; } +		bool full()  {return mFirst && mSecond; } +		bool hasElement(LLMemoryChunk* chunk) {return mFirst == chunk || mSecond == chunk;} + +	private: +		LLMemoryChunk* mFirst ; +		LLMemoryChunk* mSecond ; +	}; +	std::vector<LLChunkHashElement> mChunkHashList ; +}; + +class LL_COMMON_API LLPrivateMemoryPoolManager +{ +private: +	LLPrivateMemoryPoolManager(BOOL enabled) ; +	~LLPrivateMemoryPoolManager() ; + +public:	 +	static LLPrivateMemoryPoolManager* getInstance() ; +	static void initClass(BOOL enabled) ; +	static void destroyClass() ; + +	LLPrivateMemoryPool* newPool(S32 type) ; +	void deletePool(LLPrivateMemoryPool* pool) ; + +private: +	static LLPrivateMemoryPoolManager* sInstance ; +	std::vector<LLPrivateMemoryPool*> mPoolList ; +	BOOL mPrivatePoolEnabled; + +public: +	//debug and statistics info. +	void updateStatistics() ; + +	U32 mTotalReservedSize ; +	U32 mTotalAllocatedSize ; + +public: +#if __DEBUG_PRIVATE_MEM__ +	static char* allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) ;	 +	 +	typedef std::map<char*, std::string> mem_allocation_info_t ; +	static mem_allocation_info_t sMemAllocationTracker; +#else +	static char* allocate(LLPrivateMemoryPool* poolp, U32 size) ;	 +#endif +	static void  freeMem(LLPrivateMemoryPool* poolp, void* addr) ; +}; + +//------------------------------------------------------------------------------------- +#if __DEBUG_PRIVATE_MEM__ +#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size), __FUNCTION__, __LINE__) +#else +#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size)) +#endif +#define FREE_MEM(poolp, addr) LLPrivateMemoryPoolManager::freeMem((poolp), (addr)) +//------------------------------------------------------------------------------------- + +// +//the below singleton is used to test the private memory pool. +// +#if 0 +class LL_COMMON_API LLPrivateMemoryPoolTester +{ +private: +	LLPrivateMemoryPoolTester() ; +	~LLPrivateMemoryPoolTester() ; + +public: +	static LLPrivateMemoryPoolTester* getInstance() ; +	static void destroy() ; + +	void run(S32 type) ;	 + +private: +	void correctnessTest() ; +	void performanceTest() ; +	void fragmentationtest() ; + +	void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ; +	void testAndTime(U32 size, U32 times) ; + +#if 0 +public: +	void* operator new(size_t size) +	{ +		return (void*)sPool->allocate(size) ; +	} +    void  operator delete(void* addr) +	{ +		sPool->freeMem(addr) ; +	} +	void* operator new[](size_t size) +	{ +		return (void*)sPool->allocate(size) ; +	} +    void  operator delete[](void* addr) +	{ +		sPool->freeMem(addr) ; +	} +#endif + +private: +	static LLPrivateMemoryPoolTester* sInstance; +	static LLPrivateMemoryPool* sPool ; +	static LLPrivateMemoryPool* sThreadedPool ; +}; +#if 0 +//static +void* LLPrivateMemoryPoolTester::operator new(size_t size) +{ +	return (void*)sPool->allocate(size) ; +} + +//static +void  LLPrivateMemoryPoolTester::operator delete(void* addr) +{ +	sPool->free(addr) ; +} + +//static +void* LLPrivateMemoryPoolTester::operator new[](size_t size) +{ +	return (void*)sPool->allocate(size) ; +} + +//static +void  LLPrivateMemoryPoolTester::operator delete[](void* addr) +{ +	sPool->free(addr) ; +} +#endif +#endif  // LLRefCount moved to llrefcount.h  // LLPointer moved to llpointer.h 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/llsingleton.h b/indra/llcommon/llsingleton.h index 00757be277..49d99f2cd0 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -114,8 +114,7 @@ private:  		~SingletonInstanceData()  		{ -			SingletonInstanceData& data = getData(); -			if (data.mInitState != DELETED) +			if (mInitState != DELETED)  			{  				deleteSingleton();  			} @@ -130,7 +129,26 @@ public:  		data.mInitState = DELETED;  	} -	// Can be used to control when the singleton is deleted.  Not normally needed. +	/** +	 * @brief Immediately delete the singleton. +	 * +	 * A subsequent call to LLProxy::getInstance() will construct a new +	 * instance of the class. +	 * +	 * LLSingletons are normally destroyed after main() has exited and the C++ +	 * runtime is cleaning up statically-constructed objects. Some classes +	 * derived from LLSingleton have objects that are part of a runtime system +	 * that is terminated before main() exits. Calling the destructor of those +	 * objects after the termination of their respective systems can cause +	 * crashes and other problems during termination of the project. Using this +	 * method to destroy the singleton early can prevent these crashes. +	 * +	 * An example where this is needed is for a LLSingleton that has an APR +	 * object as a member that makes APR calls on destruction. The APR system is +	 * shut down explicitly before main() exits. This causes a crash on exit. +	 * Using this method before the call to apr_terminate() and NOT calling +	 * getInstance() again will prevent the crash. +	 */  	static void deleteSingleton()  	{  		delete getData().mSingletonInstance; diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index f3b48b0156..e7fe656808 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -936,13 +936,18 @@ LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr,  {  	const std::string delims (","); -	// Find the first ] -	size_type pos2 = instr.find(']', start); +	// Find the first [ +	size_type pos1 = instr.find('[', start); +	if (pos1 == std::string::npos) +		return std::string::npos; + +	//Find the first ] after the initial [ +	size_type pos2 = instr.find(']', pos1);  	if (pos2 == std::string::npos)  		return std::string::npos; -	// Find the last [ before ] -	size_type pos1 = instr.find_last_of('[', pos2-1); +	// Find the last [ before ] in case of nested [[]] +	pos1 = instr.find_last_of('[', pos2-1);  	if (pos1 == std::string::npos || pos1 < start)  		return std::string::npos; diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 4063cc730b..bdde1b5c48 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -36,6 +36,12 @@  #include <sched.h>  #endif +#if !LL_DARWIN +U32 ll_thread_local local_thread_ID = 0; +#endif  + +U32 LLThread::sIDIter = 0; +  //----------------------------------------------------------------------------  // Usage:  // void run_func(LLThread* thread) @@ -56,12 +62,6 @@  //   //---------------------------------------------------------------------------- -#if !LL_DARWIN -U32 ll_thread_local sThreadID = 0; -#endif  - -U32 LLThread::sIDIter = 0; -  LL_COMMON_API void assert_main_thread()  {  	static U32 s_thread_id = LLThread::currentID(); @@ -79,9 +79,12 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap  	LLThread *threadp = (LLThread *)datap;  #if !LL_DARWIN -	sThreadID = threadp->mID; +	local_thread_ID = threadp->mID;  #endif +	// Create a thread local data. +	LLThreadLocalData::create(threadp); +  	// Run the user supplied function  	threadp->run(); @@ -94,40 +97,22 @@ 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)  { -	mID = ++sIDIter; +	mID = ++sIDIter; //flaw: assume this is called only in the main thread! -	// Thread creation probably CAN be paranoid about APR being initialized, if necessary -	if (poolp) -	{ -		mIsLocalPool = FALSE; -		mAPRPoolp = poolp; -	} -	else -	{ -		mIsLocalPool = TRUE; -		apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread -	} -	mRunCondition = new LLCondition(mAPRPoolp); - -	mLocalAPRFilePoolp = NULL ; +	mRunCondition = new LLCondition;  }  LLThread::~LLThread()  {  	shutdown(); - -	if(mLocalAPRFilePoolp) -	{ -		delete mLocalAPRFilePoolp ; -		mLocalAPRFilePoolp = NULL ; -	}  }  void LLThread::shutdown() @@ -164,7 +149,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; @@ -174,15 +159,8 @@ void LLThread::shutdown()  	delete mRunCondition;  	mRunCondition = 0; -	 -	if (mIsLocalPool && mAPRPoolp) -	{ -		apr_pool_destroy(mAPRPoolp); -		mAPRPoolp = 0; -	}  } -  void LLThread::start()  {  	llassert(isStopped()); @@ -191,7 +169,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)  	{	 @@ -216,7 +194,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  	}	  } @@ -224,7 +202,7 @@ void LLThread::unpause()  {  	if (mPaused)  	{ -		mPaused = 0; +		mPaused = false;  	}  	wake(); // wake up the thread if necessary @@ -301,116 +279,76 @@ void LLThread::wakeLocked()  	}  } -//============================================================================ - -LLMutex::LLMutex(apr_pool_t *poolp) : -	mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD) -{ -	//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 -	//bad assertion, the subclass LLSignal might be "locked", and that's OK -	//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() -{ -#if LL_DARWIN -	if (mLockingThread == LLThread::currentID()) -#else -	if (mLockingThread == sThreadID) -#endif -	{ //redundant lock -		mCount++; -		return; -	} -	 -	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 +	// Create the thread-local data for the main thread (this function is called by the main thread). +	LLThreadLocalData::create(NULL); -#if LL_DARWIN -	mLockingThread = LLThread::currentID(); -#else -	mLockingThread = sThreadID; +#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 (mCount > 0) -	{ //not the root unlock -		mCount--; -		return; -	} -	 -#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 - -	mLockingThread = NO_THREAD; -	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; -	} -	else -	{ -		apr_thread_mutex_unlock(mAPRMutexp); -		return false; +		threadp->mThreadLocalData = new_tld;  	} +	apr_status_t status = apr_threadkey_private_set(new_tld, sThreadLocalDataKey); +	llassert_always(status == APR_SUCCESS);  } -U32 LLMutex::lockingThread() const +//static +LLThreadLocalData& LLThreadLocalData::tldata(void)  { -	return mLockingThread; +	if (!sThreadLocalDataKey) +	{ +		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());  } @@ -423,15 +361,6 @@ LLCondition::~LLCondition()  void LLCondition::wait()  { -	if (!isLocked()) -	{ //mAPRMutexp MUST be locked before calling apr_thread_cond_wait -		apr_thread_mutex_lock(mAPRMutexp); -#if MUTEX_DEBUG -		// avoid asserts on destruction in non-release builds -		U32 id = LLThread::currentID(); -		mIsLocked[id] = TRUE; -#endif -	}  	apr_thread_cond_wait(mAPRCondp, mAPRMutexp);  } @@ -446,6 +375,44 @@ void LLCondition::broadcast()  }  //============================================================================ +LLMutexBase::LLMutexBase() : +	mLockingThread(NO_THREAD), +	mCount(0) +{ +} + +void LLMutexBase::lock()  +{  +#if LL_DARWIN +	if (mLockingThread == LLThread::currentID()) +#else +	if (mLockingThread == local_thread_ID) +#endif +	{ //redundant lock +		mCount++; +		return; +	} + +	apr_thread_mutex_lock(mAPRMutexp);  + +#if LL_DARWIN +	mLockingThread = LLThread::currentID(); +#else +	mLockingThread = local_thread_ID; +#endif +} + +void LLMutexBase::unlock()  +{  +	if (mCount > 0) +	{ //not the root unlock +		mCount--; +		return; +	} +	mLockingThread = NO_THREAD; + +	apr_thread_mutex_unlock(mAPRMutexp);  +}  //---------------------------------------------------------------------------- @@ -457,7 +424,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 40291a2569..c732e3bc77 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -29,7 +29,13 @@  #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; @@ -41,6 +47,22 @@ class LLCondition;  #define ll_thread_local __thread  #endif +class LL_COMMON_API LLThreadLocalData +{ +private: +	static apr_threadkey_t* sThreadLocalDataKey; + +public: +	// Thread-local memory pools. +	LLAPRRootPool mRootPool; +	LLVolatileAPRPool mVolatileAPRPool; + +	static void init(void); +	static void destroy(void* thread_local_data); +	static void create(LLThread* pthread); +	static LLThreadLocalData& tldata(void); +}; +  class LL_COMMON_API LLThread  {  private: @@ -54,7 +76,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 @@ -69,7 +91,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(); @@ -83,13 +105,11 @@ public:  	// this kicks off the apr thread  	void start(void); -	apr_pool_t *getAPRPool() { return mAPRPoolp; } -	LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; } - -	U32 getID() const { return mID; } +	// 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); @@ -99,15 +119,11 @@ protected:  	LLCondition*		mRunCondition;  	apr_thread_t		*mAPRThreadp; -	apr_pool_t			*mAPRPoolp; -	BOOL				mIsLocalPool;  	EThreadStatus		mStatus;  	U32					mID; - -	//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(); @@ -137,7 +153,15 @@ 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:  	typedef enum @@ -145,32 +169,73 @@ public:  		NO_THREAD = 0xFFFFFFFF  	} e_locking_thread; -	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 -	U32 lockingThread() const; //get ID of locking thread -	 +	LLMutexBase() ; + +	void lock() ; +	void unlock() ; +	// Returns true if lock was obtained successfully. +	bool trylock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); } + +	// non-blocking, but does do a lock/unlock so not free +	bool isLocked() { bool is_not_locked = trylock(); if (is_not_locked) unlock(); return !is_not_locked; } +  protected: -	apr_thread_mutex_t *mAPRMutexp; +	// mAPRMutexp is initialized and uninitialized in the derived class. +	apr_thread_mutex_t* mAPRMutexp;  	mutable U32			mCount;  	mutable U32			mLockingThread; -	 -	apr_pool_t			*mAPRPoolp; -	BOOL				mIsLocalPool; -	 -#if MUTEX_DEBUG -	std::map<U32, BOOL> mIsLocked; +}; + +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: +	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 @@ -181,10 +246,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(); @@ -194,7 +259,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/llversionviewer.h b/indra/llcommon/llversionviewer.h index 324507fe7a..ef55cfec89 100755 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -29,7 +29,7 @@  const S32 LL_VERSION_MAJOR = 3;  const S32 LL_VERSION_MINOR = 0; -const S32 LL_VERSION_PATCH = 4; +const S32 LL_VERSION_PATCH = 5;  const S32 LL_VERSION_BUILD = 0;  const char * const LL_CHANNEL = "Second Life Developer"; 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;  }; diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 80b35bbdc3..b34d1c5fd3 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -40,6 +40,7 @@  #include <boost/scoped_ptr.hpp>  // other Linden headers  #include "../test/lltut.h" +#include "wrapllerrs.h"  struct Keyed: public LLInstanceTracker<Keyed, std::string>  { @@ -165,4 +166,67 @@ namespace tut          ensure_equals("unreported instance", instances.size(), 0);      } + +    template<> template<> +    void object::test<5>() +    { +        set_test_name("delete Keyed with outstanding instance_iter"); +        std::string what; +        Keyed* keyed = new Keyed("one"); +        { +            WrapLL_ERRS wrapper; +            Keyed::instance_iter i(Keyed::beginInstances()); +            try +            { +                delete keyed; +            } +            catch (const WrapLL_ERRS::FatalException& e) +            { +                what = e.what(); +            } +        } +        ensure(! what.empty()); +    } + +    template<> template<> +    void object::test<6>() +    { +        set_test_name("delete Keyed with outstanding key_iter"); +        std::string what; +        Keyed* keyed = new Keyed("one"); +        { +            WrapLL_ERRS wrapper; +            Keyed::key_iter i(Keyed::beginKeys()); +            try +            { +                delete keyed; +            } +            catch (const WrapLL_ERRS::FatalException& e) +            { +                what = e.what(); +            } +        } +        ensure(! what.empty()); +    } + +    template<> template<> +    void object::test<7>() +    { +        set_test_name("delete Unkeyed with outstanding instance_iter"); +        std::string what; +        Unkeyed* unkeyed = new Unkeyed; +        { +            WrapLL_ERRS wrapper; +            Unkeyed::instance_iter i(Unkeyed::beginInstances()); +            try +            { +                delete unkeyed; +            } +            catch (const WrapLL_ERRS::FatalException& e) +            { +                what = e.what(); +            } +        } +        ensure(! what.empty()); +    }  } // namespace tut diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp new file mode 100644 index 0000000000..385289aefe --- /dev/null +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -0,0 +1,76 @@ +/**  + * @file llsingleton_test.cpp + * @date 2011-08-11 + * @brief Unit test for the LLSingleton class + * + * $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$ + */ + +#include "linden_common.h" + +#include "llsingleton.h" +#include "../test/lltut.h" + +namespace tut +{ +	struct singleton +	{ +		// We need a class created with the LLSingleton template to test with. +		class LLSingletonTest: public LLSingleton<LLSingletonTest> +		{ + +		}; +	}; + +	typedef test_group<singleton> singleton_t; +	typedef singleton_t::object singleton_object_t; +	tut::singleton_t tut_singleton("LLSingleton"); + +	template<> template<> +	void singleton_object_t::test<1>() +	{ + +	} +	template<> template<> +	void singleton_object_t::test<2>() +	{ +		LLSingletonTest* singleton_test = LLSingletonTest::getInstance(); +		ensure(singleton_test); +	} +	template<> template<> +	void singleton_object_t::test<3>() +	{ +		//Construct the instance +		LLSingletonTest::getInstance(); +		ensure(LLSingletonTest::instanceExists()); + +		//Delete the instance +		LLSingletonTest::deleteSingleton(); +		ensure(LLSingletonTest::destroyed()); +		ensure(!LLSingletonTest::instanceExists()); + +		//Construct it again. +		LLSingletonTest* singleton_test = LLSingletonTest::getInstance(); +		ensure(singleton_test); +		ensure(LLSingletonTest::instanceExists()); +	} +} diff --git a/indra/llcommon/tests/llstring_test.cpp b/indra/llcommon/tests/llstring_test.cpp index 304e91ed92..6a1cbf652a 100644 --- a/indra/llcommon/tests/llstring_test.cpp +++ b/indra/llcommon/tests/llstring_test.cpp @@ -624,6 +624,14 @@ namespace tut  		subcount = LLStringUtil::format(s, fmt_map);  		ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "?Am I not a long string?short[A]bbbaaaba[A]");  		ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); +		 +		// Test on nested brackets +		std::string srcs6 = "[[TRICK1]][[A]][[B]][[AAA]][[BBB]][[TRICK2]][[KEYLONGER]][[KEYSHORTER]]?[[DELETE]]"; +		s = srcs6; +		subcount = LLStringUtil::format(s, fmt_map); +		ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "[[A]][a][b][aaa][bbb][[A]][short][Am I not a long string?]?[]"); +		ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); +  		// Test an assorted substitution  		std::string srcs8 = "foo[DELETE]bar?"; diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 331a1692ee..514ef6011f 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -414,8 +414,7 @@ bool LLCrashLogger::init()  		return false;  	} -	gServicePump = new LLPumpIO(gAPRPoolp); -	gServicePump->prime(gAPRPoolp); +	gServicePump = new LLPumpIO;  	LLHTTPClient::setPump(*gServicePump);  	//If we've opened the crash logger, assume we can delete the marker file if it exists diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index f0d15d9607..23adbf68c8 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -39,6 +39,7 @@  #include "llimagepng.h"  #include "llimagedxt.h"  #include "llimageworker.h" +#include "llmemory.h"  //---------------------------------------------------------------------------  // LLImage @@ -47,11 +48,14 @@  //static  std::string LLImage::sLastErrorMessage;  LLMutex* LLImage::sMutex = NULL; +LLPrivateMemoryPool* LLImageBase::sPrivatePoolp = NULL ;  //static  void LLImage::initClass()  { -	sMutex = new LLMutex(NULL); +	sMutex = new LLMutex; + +	LLImageBase::createPrivatePool() ;  }  //static @@ -59,6 +63,8 @@ void LLImage::cleanupClass()  {  	delete sMutex;  	sMutex = NULL; + +	LLImageBase::destroyPrivatePool() ;  }  //static @@ -97,6 +103,25 @@ LLImageBase::~LLImageBase()  	deleteData(); // virtual  } +//static  +void LLImageBase::createPrivatePool()  +{ +	if(!sPrivatePoolp) +	{ +		sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC_THREADED) ; +	} +} +	 +//static  +void LLImageBase::destroyPrivatePool()  +{ +	if(sPrivatePoolp) +	{ +		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ; +		sPrivatePoolp = NULL ; +	} +} +  // virtual  void LLImageBase::dump()  { @@ -130,7 +155,7 @@ void LLImageBase::sanityCheck()  // virtual  void LLImageBase::deleteData()  { -	delete[] mData; +	FREE_MEM(sPrivatePoolp, mData) ;  	mData = NULL;  	mDataSize = 0;  } @@ -167,7 +192,7 @@ U8* LLImageBase::allocateData(S32 size)  	{  		deleteData(); // virtual  		mBadBufferAllocation = false ; -		mData = new U8[size]; +		mData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);  		if (!mData)  		{  			llwarns << "allocate image data: " << size << llendl; @@ -185,7 +210,7 @@ U8* LLImageBase::allocateData(S32 size)  U8* LLImageBase::reallocateData(S32 size)  {  	LLMemType mt1(mMemType); -	U8 *new_datap = new U8[size]; +	U8 *new_datap = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);  	if (!new_datap)  	{  		llwarns << "Out of memory in LLImageBase::reallocateData" << llendl; @@ -195,7 +220,7 @@ U8* LLImageBase::reallocateData(S32 size)  	{  		S32 bytes = llmin(mDataSize, size);  		memcpy(new_datap, mData, bytes);	/* Flawfinder: ignore */ -		delete[] mData; +		FREE_MEM(sPrivatePoolp, mData) ;  	}  	mData = new_datap;  	mDataSize = size; @@ -341,6 +366,7 @@ BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)  	return TRUE;  } +#if 0  U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const  {  	LLMemType mt1(mMemType); @@ -361,6 +387,7 @@ U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const  	}  	return data;  } +#endif  BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,  							 const U8 *data, U32 stride, BOOL reverse_y) @@ -830,6 +857,7 @@ void LLImageRaw::copyScaled( LLImageRaw* src )  	}  } +#if 0  //scale down image by not blending a pixel with its neighbors.  BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)  { @@ -853,7 +881,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)  	ratio_x -= 1.0f ;  	ratio_y -= 1.0f ; -	U8* new_data = new U8[new_data_size] ; +	U8* new_data = allocateMemory(new_data_size) ;  	llassert_always(new_data != NULL) ;  	U8* old_data = getData() ; @@ -875,6 +903,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)  	return TRUE ;  } +#endif  BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )  { @@ -1506,6 +1535,7 @@ void LLImageFormatted::setData(U8 *data, S32 size)  	{  		deleteData();  		setDataAndSize(data, size); // Access private LLImageBase members +  		sGlobalFormattedMemory += getDataSize();  	}  } @@ -1524,7 +1554,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size)  			S32 newsize = cursize + size;  			reallocateData(newsize);  			memcpy(getData() + cursize, data, size); -			delete[] data; +			FREE_MEM(LLImageBase::getPrivatePool(), data);  		}  	}  } @@ -1536,8 +1566,7 @@ BOOL LLImageFormatted::load(const std::string &filename)  	resetLastError();  	S32 file_size = 0; -	LLAPRFile infile ; -	infile.open(filename, LL_APR_RB, NULL, &file_size); +	LLAPRFile infile(filename, LL_APR_RB, &file_size);  	apr_file_t* apr_file = infile.getFileHandle();  	if (!apr_file)  	{ @@ -1572,8 +1601,7 @@ BOOL LLImageFormatted::save(const std::string &filename)  {  	resetLastError(); -	LLAPRFile outfile ; -	outfile.open(filename, LL_APR_WB); +	LLAPRFile outfile(filename, LL_APR_WB);  	if (!outfile.getFileHandle())  	{  		setLastError("Unable to open file for writing", filename); diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index c464c3b2b6..4469c9e860 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -29,7 +29,6 @@  #include "lluuid.h"  #include "llstring.h" -//#include "llmemory.h"  #include "llthread.h"  #include "llmemtype.h" @@ -69,6 +68,7 @@ const S32 MAX_IMG_PACKET_SIZE = 1000;  class LLImageFormatted;  class LLImageRaw;  class LLColor4U; +class LLPrivateMemoryPool;  typedef enum e_image_codec  { @@ -140,7 +140,7 @@ public:  protected:  	// special accessor to allow direct setting of mData and mDataSize by LLImageFormatted -	void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; } +	void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; }	  public:  	static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels); @@ -151,6 +151,10 @@ public:  	static EImageCodec getCodecFromExtension(const std::string& exten); +	static void createPrivatePool() ; +	static void destroyPrivatePool() ; +	static LLPrivateMemoryPool* getPrivatePool() {return sPrivatePoolp;} +  private:  	U8 *mData;  	S32 mDataSize; @@ -162,6 +166,8 @@ private:  	bool mBadBufferAllocation ;  	bool mAllowOverSize ; + +	static LLPrivateMemoryPool* sPrivatePoolp ;  public:  	LLMemType::DeclareMemType& mMemType; // debug  }; @@ -185,7 +191,7 @@ public:  	BOOL resize(U16 width, U16 height, S8 components); -	U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const; +	//U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const;  	BOOL setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,  					 const U8 *data, U32 stride = 0, BOOL reverse_y = FALSE); @@ -197,7 +203,7 @@ public:  	void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);  	void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);  	BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE ); -	BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ; +	//BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;  	// Fill the buffer with a constant color  	void fill( const LLColor4U& color ); diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp index c6bfa50b40..926c749145 100644 --- a/indra/llimage/llimagedimensionsinfo.cpp +++ b/indra/llimage/llimagedimensionsinfo.cpp @@ -40,7 +40,7 @@ bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)  	mSrcFilename = src_filename;  	S32 file_size = 0; -	apr_status_t s = mInfile.open(src_filename, LL_APR_RB, NULL, &file_size); +	apr_status_t s = mInfile.open(src_filename, LL_APR_RB, LLAPRFile::long_lived, &file_size);  	if (s != APR_SUCCESS)  	{ diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 4bd3efddaa..2867f5e6f0 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -429,7 +429,7 @@ bool LLImageDXT::convertToDXR()  	S32 nmips = calcNumMips(width,height);  	S32 total_bytes = getDataSize();  	U8* olddata = getData(); -	U8* newdata = new U8[total_bytes]; +	U8* newdata = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_bytes);  	if (!newdata)  	{  		llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl; diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 44e6b89dd3..8c5dc63e9d 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -370,8 +370,7 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)  	resetLastError();  	S32 file_size = 0; -	LLAPRFile infile ; -	infile.open(filename, LL_APR_RB, NULL, &file_size); +	LLAPRFile infile(filename, LL_APR_RB, &file_size);  	apr_file_t* apr_file = infile.getFileHandle() ;  	if (!apr_file)  	{ @@ -385,14 +384,14 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)  	}  	else  	{ -		U8 *data = new U8[file_size]; +		U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size);  		apr_size_t bytes_read = file_size;  		apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read	  		infile.close() ;  		if (s != APR_SUCCESS || (S32)bytes_read != file_size)  		{ -			delete[] data; +			FREE_MEM(LLImageBase::getPrivatePool(), data);  			setLastError("Unable to read entire file");  			res = FALSE;  		} diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 28dc3bd313..2c6d6f31ea 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -35,20 +35,18 @@  LLImageDecodeThread::LLImageDecodeThread(bool threaded)  	: LLQueuedThread("imagedecode", threaded)  { -	mCreationMutex = new LLMutex(getAPRPool());  }  //virtual   LLImageDecodeThread::~LLImageDecodeThread()  { -	delete mCreationMutex ;  }  // MAIN THREAD  // virtual  S32 LLImageDecodeThread::update(U32 max_time_ms)  { -	LLMutexLock lock(mCreationMutex); +	LLMutexLock lock(&mCreationMutex);  	for (creation_list_t::iterator iter = mCreationList.begin();  		 iter != mCreationList.end(); ++iter)  	{ @@ -71,7 +69,7 @@ S32 LLImageDecodeThread::update(U32 max_time_ms)  LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image,   	U32 priority, S32 discard, BOOL needs_aux, Responder* responder)  { -	LLMutexLock lock(mCreationMutex); +	LLMutexLock lock(&mCreationMutex);  	handle_t handle = generateHandle();  	mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));  	return handle; @@ -81,7 +79,7 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted*  // Returns the size of the mutex guarded list as an indication of sanity  S32 LLImageDecodeThread::tut_size()  { -	LLMutexLock lock(mCreationMutex); +	LLMutexLock lock(&mCreationMutex);  	S32 res = mCreationList.size();  	return res;  } diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index c684222fa5..6a24b7522a 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -98,7 +98,7 @@ private:  	};  	typedef std::list<creation_info> creation_list_t;  	creation_list_t mCreationList; -	LLMutex* mCreationMutex; +	LLMutex mCreationMutex;  };  #endif diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index c60b750088..42180197fe 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -49,7 +49,7 @@ LLVolumeMgr::LLVolumeMgr()  {  	// the LLMutex magic interferes with easy unit testing,  	// so you now must manually call useMutex() to use it -	//mDataMutex = new LLMutex(gAPRPoolp); +	//mDataMutex = new LLMutex;  }  LLVolumeMgr::~LLVolumeMgr() @@ -216,7 +216,7 @@ void LLVolumeMgr::useMutex()  {   	if (!mDataMutex)  	{ -		mDataMutex = new LLMutex(gAPRPoolp); +		mDataMutex = new LLMutex;  	}  } diff --git a/indra/llmath/tests/v3math_test.cpp b/indra/llmath/tests/v3math_test.cpp index df7a77002f..e4ae1c10ef 100644 --- a/indra/llmath/tests/v3math_test.cpp +++ b/indra/llmath/tests/v3math_test.cpp @@ -564,4 +564,22 @@ namespace tut  		z1 = U8_to_F32(F32_to_U8(z, lowerz, upperz), lowerz, upperz);  		ensure("2:quantize8: Fail ", is_approx_equal(x1, vec3a.mV[VX]) && is_approx_equal(y1, vec3a.mV[VY]) && is_approx_equal(z1, vec3a.mV[VZ]));  	} + +	template<> template<> +	void v3math_object::test<35>() +	{ +		LLSD sd = LLSD::emptyArray(); +		sd[0] = 1.f; + +		LLVector3 parsed_1(sd); +		ensure("1:LLSD parse: Fail ", is_approx_equal(parsed_1.mV[VX], 1.f) && is_approx_equal(parsed_1.mV[VY], 0.f) && is_approx_equal(parsed_1.mV[VZ], 0.f)); + +		sd[1] = 2.f; +		LLVector3 parsed_2(sd); +		ensure("2:LLSD parse: Fail ", is_approx_equal(parsed_2.mV[VX], 1.f) && is_approx_equal(parsed_2.mV[VY], 2.f) && is_approx_equal(parsed_2.mV[VZ], 0.f)); + +		sd[2] = 3.f; +		LLVector3 parsed_3(sd); +		ensure("3:LLSD parse: Fail ", is_approx_equal(parsed_3.mV[VX], 1.f) && is_approx_equal(parsed_3.mV[VY], 2.f) && is_approx_equal(parsed_3.mV[VZ], 3.f)); +	}  } diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp index 5a67035ed1..fab9858b69 100644 --- a/indra/llmessage/llares.cpp +++ b/indra/llmessage/llares.cpp @@ -28,6 +28,7 @@  #include "linden_common.h"  #include "llares.h" +#include "llscopedvolatileaprpool.h"  #include <ares_dns.h>  #include <ares_version.h> @@ -464,11 +465,6 @@ void LLAres::search(const std::string &query, LLResType type,  bool LLAres::process(U64 timeout)  { -	if (!gAPRPoolp) -	{ -		ll_init_apr(); -	} -  	ares_socket_t socks[ARES_GETSOCK_MAXNUM];  	apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];  	apr_int32_t nsds = 0;	 @@ -482,10 +478,7 @@ bool LLAres::process(U64 timeout)  		return nsds > 0;  	} -	apr_status_t status; -	LLAPRPool pool; -	status = pool.getStatus() ; -	ll_apr_assert_status(status); +	LLScopedVolatileAPRPool scoped_pool;  	for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)  	{ @@ -502,7 +495,7 @@ bool LLAres::process(U64 timeout)  		apr_socket_t *aprSock = NULL; -		status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool()); +		apr_status_t status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], scoped_pool);  		if (status != APR_SUCCESS)  		{  			ll_apr_warn_status(status); @@ -511,7 +504,7 @@ bool LLAres::process(U64 timeout)  		aprFds[nactive].desc.s = aprSock;  		aprFds[nactive].desc_type = APR_POLL_SOCKET; -		aprFds[nactive].p = pool.getAPRPool(); +		aprFds[nactive].p = scoped_pool;  		aprFds[nactive].rtnevents = 0;  		aprFds[nactive].client_data = &socks[i]; @@ -520,7 +513,7 @@ bool LLAres::process(U64 timeout)  	if (nactive > 0)  	{ -		status = apr_poll(aprFds, nactive, &nsds, timeout); +		apr_status_t status = apr_poll(aprFds, nactive, &nsds, timeout);  		if (status != APR_SUCCESS && status != APR_TIMEUP)  		{ diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index bfdf49c74b..14e169c6b1 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -499,7 +499,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,  	//don't verify host name so urls with scrubbed host names will work (improves DNS performance)  	setopt(CURLOPT_SSL_VERIFYHOST, 0); -	setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT); +	setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT));  	setoptString(CURLOPT_URL, url); @@ -531,7 +531,7 @@ LLCurl::Multi::Multi()  	mThreaded = LLCurl::sMultiThreaded && LLThread::currentID() == sMainThreadID;  	if (mThreaded)  	{ -		mSignal = new LLCondition(NULL); +		mSignal = new LLCondition();  	}  	else  	{ @@ -1178,13 +1178,13 @@ void LLCurl::initClass(bool multi_threaded)  	check_curl_code(code); -	Easy::sHandleMutex = new LLMutex(NULL); +	Easy::sHandleMutex = new LLMutex();  #if SAFE_SSL  	S32 mutex_count = CRYPTO_num_locks();  	for (S32 i=0; i<mutex_count; i++)  	{ -		sSSLMutex.push_back(new LLMutex(NULL)); +		sSSLMutex.push_back(new LLMutex);  	}  	CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);  	CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback); @@ -1213,3 +1213,13 @@ void LLCurl::cleanupClass()  }  const unsigned int LLCurl::MAX_REDIRECTS = 5; + +// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace. +void LLCurlFF::check_easy_code(CURLcode code) +{ +	check_curl_code(code); +} +void LLCurlFF::check_multi_code(CURLMcode code) +{ +	check_curl_multi_code(code); +} diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index 5ab4dc35b9..213b281e72 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -371,7 +371,11 @@ private:  	bool mResultReturned;  }; -void check_curl_code(CURLcode code); -void check_curl_multi_code(CURLMcode code); +// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace. +namespace LLCurlFF +{ +	void check_easy_code(CURLcode code); +	void check_multi_code(CURLMcode code); +}  #endif // LL_LLCURL_H diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 73e8a69085..920a57ab55 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -963,13 +963,9 @@ private:  // static -LLHTTPNode& LLIOHTTPServer::create( -	apr_pool_t* pool, LLPumpIO& pump, U16 port) +LLHTTPNode& LLIOHTTPServer::create(LLPumpIO& pump, U16 port)  { -	LLSocket::ptr_t socket = LLSocket::create( -        pool, -        LLSocket::STREAM_TCP, -        port); +	LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP, port);      if(!socket)      {          llerrs << "Unable to initialize socket" << llendl; @@ -978,7 +974,7 @@ LLHTTPNode& LLIOHTTPServer::create(      LLHTTPResponseFactory* factory = new LLHTTPResponseFactory;  	boost::shared_ptr<LLChainIOFactory> factory_ptr(factory); -    LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr); +    LLIOServerSocket* server = new LLIOServerSocket(socket, factory_ptr);  	LLPumpIO::chain_t chain;      chain.push_back(LLIOPipe::ptr_t(server)); diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h index 5c1b0531ff..2294e4b8ae 100644 --- a/indra/llmessage/lliohttpserver.h +++ b/indra/llmessage/lliohttpserver.h @@ -50,7 +50,7 @@ class LLIOHTTPServer  public:  	typedef void (*timing_callback_t)(const char* hashed_name, F32 time, void* data); -	static LLHTTPNode& create(apr_pool_t* pool, LLPumpIO& pump, U16 port); +	static LLHTTPNode& create(LLPumpIO& pump, U16 port);  	/**< Creates an HTTP wire server on the pump for the given TCP port.  	 *  	 *   Returns the root node of the new server.  Add LLHTTPNode instances diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index ee9379f205..a885ba8ee1 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -35,6 +35,7 @@  #include "llhost.h"  #include "llmemtype.h"  #include "llpumpio.h" +#include "llthread.h"  //  // constants @@ -98,51 +99,31 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock)  ///  // static -LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) +LLSocket::ptr_t LLSocket::create(EType type, U16 port)  {  	LLMemType m1(LLMemType::MTYPE_IO_TCP); -	LLSocket::ptr_t rv; -	apr_socket_t* socket = NULL; -	apr_pool_t* new_pool = NULL;  	apr_status_t status = APR_EGENERAL; - -	// create a pool for the socket -	status = apr_pool_create(&new_pool, pool); -	if(ll_apr_warn_status(status)) -	{ -		if(new_pool) apr_pool_destroy(new_pool); -		return rv; -	} +	LLSocket::ptr_t rv(new LLSocket);  	if(STREAM_TCP == type)  	{ -		status = apr_socket_create( -			&socket, -			APR_INET, -			SOCK_STREAM, -			APR_PROTO_TCP, -			new_pool); +		status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, rv->mPool());  	}  	else if(DATAGRAM_UDP == type)  	{ -		status = apr_socket_create( -			&socket, -			APR_INET, -			SOCK_DGRAM, -			APR_PROTO_UDP, -			new_pool); +		status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, rv->mPool());  	}  	else  	{ -		if(new_pool) apr_pool_destroy(new_pool); +		rv.reset();  		return rv;  	}  	if(ll_apr_warn_status(status))  	{ -		if(new_pool) apr_pool_destroy(new_pool); +		rv->mSocket = NULL; +		rv.reset();  		return rv;  	} -	rv = ptr_t(new LLSocket(socket, new_pool));  	if(port > 0)  	{  		apr_sockaddr_t* sa = NULL; @@ -152,7 +133,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)  			APR_UNSPEC,  			port,  			0, -			new_pool); +			rv->mPool());  		if(ll_apr_warn_status(status))  		{  			rv.reset(); @@ -160,8 +141,8 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)  		}  		// This allows us to reuse the address on quick down/up. This  		// is unlikely to create problems. -		ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1)); -		status = apr_socket_bind(socket, sa); +		ll_apr_warn_status(apr_socket_opt_set(rv->mSocket, APR_SO_REUSEADDR, 1)); +		status = apr_socket_bind(rv->mSocket, sa);  		if(ll_apr_warn_status(status))  		{  			rv.reset(); @@ -175,7 +156,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)  			// to keep a queue of incoming connections for ACCEPT.  			lldebugs << "Setting listen state for socket." << llendl;  			status = apr_socket_listen( -				socket, +				rv->mSocket,  				LL_DEFAULT_LISTEN_BACKLOG);  			if(ll_apr_warn_status(status))  			{ @@ -196,21 +177,28 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)  }  // static -LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool) +LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_socket)  {  	LLMemType m1(LLMemType::MTYPE_IO_TCP); -	LLSocket::ptr_t rv; -	if(!socket) +	if (!listen_socket->getSocket()) +	{ +		status = APR_ENOSOCKET; +		return LLSocket::ptr_t(); +	} +	LLSocket::ptr_t rv(new LLSocket); +	lldebugs << "accepting socket" << llendl; +	status = apr_socket_accept(&rv->mSocket, listen_socket->getSocket(), rv->mPool()); +	if (status != APR_SUCCESS)  	{ +		rv->mSocket = NULL; +		rv.reset();  		return rv;  	} -	rv = ptr_t(new LLSocket(socket, pool));  	rv->mPort = PORT_EPHEMERAL;  	rv->setNonBlocking();  	return rv;  } -  bool LLSocket::blockingConnect(const LLHost& host)  {  	if(!mSocket) return false; @@ -223,7 +211,7 @@ bool LLSocket::blockingConnect(const LLHost& host)  		APR_UNSPEC,  		host.getPort(),  		0, -		mPool))) +		mPool())))  	{  		return false;  	} @@ -234,13 +222,11 @@ bool LLSocket::blockingConnect(const LLHost& host)  	return true;  } -LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool) : -	mSocket(socket), -	mPool(pool), +LLSocket::LLSocket() : +	mSocket(NULL), +	mPool(LLThread::tldata().mRootPool),  	mPort(PORT_INVALID)  { -	ll_debug_socket("Constructing wholely formed socket", mSocket); -	LLMemType m1(LLMemType::MTYPE_IO_TCP);  }  LLSocket::~LLSocket() @@ -253,11 +239,6 @@ LLSocket::~LLSocket()  		apr_socket_close(mSocket);  		mSocket = NULL;  	} -	if(mPool) -	{ -		apr_pool_destroy(mPool); -		mPool = NULL; -	}  }  // See http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html#ss13.4 @@ -539,10 +520,8 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(  ///  LLIOServerSocket::LLIOServerSocket( -	apr_pool_t* pool,  	LLIOServerSocket::socket_t listener,  	factory_t factory) : -	mPool(pool),  	mListenSocket(listener),  	mReactor(factory),  	mInitialized(false), @@ -604,21 +583,15 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(  	lldebugs << "accepting socket" << llendl;  	PUMP_DEBUG; -	apr_pool_t* new_pool = NULL; -	apr_status_t status = apr_pool_create(&new_pool, mPool); -	apr_socket_t* socket = NULL; -	status = apr_socket_accept( -		&socket, -		mListenSocket->getSocket(), -		new_pool); -	LLSocket::ptr_t llsocket(LLSocket::create(socket, new_pool)); +	apr_status_t status; +	LLSocket::ptr_t llsocket(LLSocket::create(status, mListenSocket));  	//EStatus rv = STATUS_ERROR; -	if(llsocket) +	if(llsocket && status == APR_SUCCESS)  	{  		PUMP_DEBUG;  		apr_sockaddr_t* remote_addr; -		apr_socket_addr_get(&remote_addr, APR_REMOTE, socket); +		apr_socket_addr_get(&remote_addr, APR_REMOTE, llsocket->getSocket());  		char* remote_host_string;  		apr_sockaddr_ip_get(&remote_host_string, remote_addr); @@ -633,7 +606,6 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(  		{  			chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket)));  			pump->addChain(chain, mResponseTimeout); -			status = STATUS_OK;  		}  		else  		{ @@ -642,7 +614,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(  	}  	else  	{ -		llwarns << "Unable to create linden socket." << llendl; +		char buf[256]; +		llwarns << "Unable to accept linden socket: " << apr_strerror(status, buf, sizeof(buf)) << llendl;  	}  	PUMP_DEBUG; @@ -655,11 +628,10 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(  #if 0  LLIODataSocket::LLIODataSocket(  	U16 suggested_port, -	U16 start_discovery_port, -	apr_pool_t* pool) :  +	U16 start_discovery_port) :  	mSocket(NULL)  { -	if(!pool || (PORT_INVALID == suggested_port)) return; +	if(PORT_INVALID == suggested_port) return;  	if(ll_apr_warn_status(apr_socket_create(&mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, pool))) return;  	apr_sockaddr_t* sa = NULL;  	if(ll_apr_warn_status(apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, suggested_port, 0, pool))) return; diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index be0f7dfcc6..f0a6f25657 100644 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -38,7 +38,6 @@   */  #include "lliopipe.h" -#include "apr_pools.h"  #include "apr_network_io.h"  #include "llchainio.h" @@ -88,34 +87,22 @@ public:  	 * socket. If you intend the socket to be known to external  	 * clients without prior port notification, do not use  	 * PORT_EPHEMERAL. -	 * @param pool The apr pool to use. A child pool will be created -	 * and associated with the socket.  	 * @param type The type of socket to create  	 * @param port The port for the socket  	 * @return A valid socket shared pointer if the call worked.  	 */  	static ptr_t create( -		apr_pool_t* pool,  		EType type,  		U16 port = PORT_EPHEMERAL);  	/**  -	 * @brief Create a LLSocket when you already have an apr socket. +	 * @brief Create a LLSocket by accepting a connection from a listen socket.  	 * -	 * This method assumes an ephemeral port. This is typically used -	 * by calls which spawn a socket such as a call to -	 * <code>accept()</code> as in the server socket. This call should -	 * not fail if you have a valid apr socket. -	 * Because of the nature of how accept() works, you are expected -	 * to create a new pool for the socket, use that pool for the -	 * accept, and pass it in here where it will be bound with the -	 * socket and destroyed at the same time. -	 * @param socket The apr socket to use  -	 * @param pool The pool used to create the socket. *NOTE: The pool -	 * passed in will be DESTROYED. +	 * @param status Output. Status of the accept if a valid listen socket was passed. +	 * @param listen_socket The listen socket to use.  	 * @return A valid socket shared pointer if the call worked.  	 */ -	static ptr_t create(apr_socket_t* socket, apr_pool_t* pool); +	static ptr_t create(apr_status_t& status, ptr_t& listen_socket);  	/**   	 * @brief Perform a blocking connect to a host. Do not use in production. @@ -146,6 +133,12 @@ public:  	apr_socket_t* getSocket() const { return mSocket; }  	/**  +	 * @brief Protected constructor since should only make sockets +	 * with one of the two <code>create()</code> calls. +	 */ +	LLSocket(void); + +	/**   	 * @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us.  	 * @param timeout Number of microseconds to wait on this socket. Any  	 * negative number means block-forever. TIMEOUT OF 0 IS NON-PORTABLE. @@ -174,8 +167,8 @@ protected:  	// The apr socket.  	apr_socket_t* mSocket; -	// our memory pool -	apr_pool_t* mPool; +	// Our memory pool. +	LLAPRPool mPool;  	// The port if we know it.  	U16 mPort; @@ -300,7 +293,7 @@ class LLIOServerSocket : public LLIOPipe  public:  	typedef LLSocket::ptr_t socket_t;  	typedef boost::shared_ptr<LLChainIOFactory> factory_t; -	LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor); +	LLIOServerSocket(socket_t listener, factory_t reactor);  	virtual ~LLIOServerSocket();  	/**  @@ -332,7 +325,6 @@ protected:  	//@}  protected: -	apr_pool_t* mPool;  	socket_t mListenSocket;  	factory_t mReactor;  	bool mInitialized; @@ -366,8 +358,7 @@ public:  	 */  	LLIODataSocket(  		U16 suggested_port, -		U16 start_discovery_port, -		apr_pool_t* pool); +		U16 start_discovery_port);  	virtual ~LLIODataSocket();  protected: diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index 08b31e9c7a..8a898ab1b0 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -50,6 +50,7 @@  #include "llstring.h"  #include "lluuid.h"  #include "net.h" +#include "llaprpool.h"  //  // constants @@ -57,7 +58,7 @@  const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;  static bool gMailEnabled = true; -static apr_pool_t* gMailPool; +static LLAPRPool gMailPool;  static apr_sockaddr_t* gSockAddr;  static apr_socket_t* gMailSocket; @@ -82,7 +83,7 @@ bool connect_smtp()  		gSockAddr->sa.sin.sin_family,  		SOCK_STREAM,  		APR_PROTO_TCP, -		gMailPool); +		gMailPool());  	if(ll_apr_warn_status(status)) return false;  	status = apr_socket_connect(gMailSocket, gSockAddr);  	if(ll_apr_warn_status(status)) @@ -139,19 +140,19 @@ BOOL LLMail::send(  }  // static -void LLMail::init(const std::string& hostname, apr_pool_t* pool) +void LLMail::init(const std::string& hostname)  {  	gMailSocket = NULL; -	if(hostname.empty() || !pool) +	if (hostname.empty())  	{ -		gMailPool = NULL;  		gSockAddr = NULL; +		gMailPool.destroy();  	}  	else  	{ -		gMailPool = pool; +		gMailPool.create(); -		// collect all the information into a socaddr sturcture. the +		// Collect all the information into a sockaddr structure. the  		// documentation is a bit unclear, but I either have to  		// specify APR_UNSPEC or not specify any flags. I am not sure  		// which option is better. @@ -161,7 +162,7 @@ void LLMail::init(const std::string& hostname, apr_pool_t* pool)  			APR_UNSPEC,  			25,  			APR_IPV4_ADDR_OK, -			gMailPool); +			gMailPool());  		ll_apr_warn_status(status);  	}  } diff --git a/indra/llmessage/llmail.h b/indra/llmessage/llmail.h index 3791714363..0a5c532088 100644 --- a/indra/llmessage/llmail.h +++ b/indra/llmessage/llmail.h @@ -27,15 +27,13 @@  #ifndef LL_LLMAIL_H  #define LL_LLMAIL_H -typedef struct apr_pool_t apr_pool_t; -  #include "llsd.h"  class LLMail  {  public:  	// if hostname is NULL, then the host is resolved as 'mail' -	static void init(const std::string& hostname, apr_pool_t* pool); +	static void init(const std::string& hostname);  	// Allow all email transmission to be disabled/enabled.  	static void enable(bool mail_enabled); diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 7628984de4..fc6e9c5193 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -228,13 +228,13 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap)  		if (LLProxy::isSOCKSProxyEnabled())  		{  			U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; -			packet_size = receive_packet(socket, reinterpret_cast<char *>(buffer)); +			packet_size = receive_packet(socket, static_cast<char*>(static_cast<void*>(buffer)));  			if (packet_size > SOCKS_HEADER_SIZE)  			{  				// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)  				memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE); -				proxywrap_t * header = reinterpret_cast<proxywrap_t *>(buffer); +				proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));  				mLastSender.setAddress(header->addr);  				mLastSender.setPort(ntohs(header->port)); @@ -353,14 +353,20 @@ BOOL LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 bu  		return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());  	} -	proxywrap_t *socks_header = reinterpret_cast<proxywrap_t *>(&mProxyWrappedSendBuffer); +	char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; + +	proxywrap_t *socks_header = static_cast<proxywrap_t*>(static_cast<void*>(&headered_send_buffer));  	socks_header->rsv   = 0;  	socks_header->addr  = host.getAddress();  	socks_header->port  = htons(host.getPort());  	socks_header->atype = ADDRESS_IPV4;  	socks_header->frag  = 0; -	memcpy(mProxyWrappedSendBuffer + SOCKS_HEADER_SIZE, send_buffer, buf_size); +	memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, send_buffer, buf_size); -	return send_packet(h_socket, (const char*) mProxyWrappedSendBuffer, buf_size + 10, LLProxy::getInstance()->getUDPProxy().getAddress(), LLProxy::getInstance()->getUDPProxy().getPort()); +	return send_packet(	h_socket, +						headered_send_buffer, +						buf_size + SOCKS_HEADER_SIZE, +						LLProxy::getInstance()->getUDPProxy().getAddress(), +						LLProxy::getInstance()->getUDPProxy().getPort());  } diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h index 7edcc834db..b214271e78 100644 --- a/indra/llmessage/llpacketring.h +++ b/indra/llmessage/llpacketring.h @@ -83,9 +83,6 @@ protected:  	LLHost mLastSender;  	LLHost mLastReceivingIF; - -	U8 mProxyWrappedSendBuffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; -  private:  	BOOL sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);  }; diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp index 3f4a6accbf..4a7d326c0e 100644 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -43,16 +43,15 @@  bool LLProxy::sUDPProxyEnabled = false;  // Some helpful TCP static functions. -static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake -static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, LLHost host); // Open a TCP channel to a given host +static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake +static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host  static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel  LLProxy::LLProxy():  		mHTTPProxyEnabled(false), -		mProxyMutex(0), +		mProxyMutex(),  		mUDPProxy(),  		mTCPProxy(), -		mPool(gAPRPoolp),  		mHTTPProxy(),  		mProxyType(LLPROXY_SOCKS),  		mAuthMethodSelected(METHOD_NOAUTH), @@ -64,14 +63,13 @@ LLProxy::LLProxy():  LLProxy::~LLProxy()  {  	stopSOCKSProxy(); -	sUDPProxyEnabled  = false; -	mHTTPProxyEnabled = false; +	disableHTTPProxy();  }  /**   * @brief Open the SOCKS 5 TCP control channel.   * - * Perform a SOCKS 5 authentication and UDP association to the proxy server. + * Perform a SOCKS 5 authentication and UDP association with the proxy server.   *   * @param proxy The SOCKS 5 server to connect to.   * @return SOCKS_OK if successful, otherwise a socks error code from llproxy.h. @@ -84,11 +82,15 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	socks_auth_request_t  socks_auth_request;  	socks_auth_response_t socks_auth_response; -	socks_auth_request.version     = SOCKS_VERSION;       // SOCKS version 5 -	socks_auth_request.num_methods = 1;                   // Sending 1 method. -	socks_auth_request.methods     = getSelectedAuthMethod(); // Send only the selected method. +	socks_auth_request.version		= SOCKS_VERSION;				// SOCKS version 5 +	socks_auth_request.num_methods	= 1;							// Sending 1 method. +	socks_auth_request.methods		= getSelectedAuthMethod();		// Send only the selected method. -	result = tcp_handshake(mProxyControlChannel, (char*)&socks_auth_request, sizeof(socks_auth_request), (char*)&socks_auth_response, sizeof(socks_auth_response)); +	result = tcp_blocking_handshake(mProxyControlChannel, +									static_cast<char*>(static_cast<void*>(&socks_auth_request)), +									sizeof(socks_auth_request), +									static_cast<char*>(static_cast<void*>(&socks_auth_response)), +									sizeof(socks_auth_response));  	if (result != APR_SUCCESS)  	{  		LL_WARNS("Proxy") << "SOCKS authentication request failed, error on TCP control channel : " << result << LL_ENDL; @@ -98,12 +100,12 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)  	{ -		LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods" << LL_ENDL; +		LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods." << LL_ENDL;  		stopSOCKSProxy();  		return SOCKS_NOT_ACCEPTABLE;  	} -	// SOCKS 5 USERNAME/PASSWORD authentication +	/* SOCKS 5 USERNAME/PASSWORD authentication */  	if (socks_auth_response.method == METHOD_PASSWORD)  	{  		// The server has requested a username/password combination @@ -115,11 +117,15 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  		password_auth[1] = socks_username.size();  		memcpy(&password_auth[2], socks_username.c_str(), socks_username.size());  		password_auth[socks_username.size() + 2] = socks_password.size(); -		memcpy(&password_auth[socks_username.size()+3], socks_password.c_str(), socks_password.size()); +		memcpy(&password_auth[socks_username.size() + 3], socks_password.c_str(), socks_password.size());  		authmethod_password_reply_t password_reply; -		result = tcp_handshake(mProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(password_reply)); +		result = tcp_blocking_handshake(mProxyControlChannel, +										password_auth, +										request_size, +										static_cast<char*>(static_cast<void*>(&password_reply)), +										sizeof(password_reply));  		delete[] password_auth;  		if (result != APR_SUCCESS) @@ -151,7 +157,11 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	// "If the client is not in possession of the information at the time of the UDP ASSOCIATE,  	//  the client MUST use a port number and address of all zeros. RFC 1928" -	result = tcp_handshake(mProxyControlChannel, (char*)&connect_request, sizeof(connect_request), (char*)&connect_reply, sizeof(connect_reply)); +	result = tcp_blocking_handshake(mProxyControlChannel, +									static_cast<char*>(static_cast<void*>(&connect_request)), +									sizeof(connect_request), +									static_cast<char*>(static_cast<void*>(&connect_reply)), +									sizeof(connect_reply));  	if (result != APR_SUCCESS)  	{  		LL_WARNS("Proxy") << "SOCKS connect request failed, error on TCP control channel : " << result << LL_ENDL; @@ -170,6 +180,7 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	mUDPProxy.setAddress(proxy.getAddress());  	// The connection was successful. We now have the UDP port to send requests that need forwarding to.  	LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL; +  	return SOCKS_OK;  } @@ -177,7 +188,8 @@ S32 LLProxy::proxyHandshake(LLHost proxy)   * @brief Initiates a SOCKS 5 proxy session.   *   * Performs basic checks on host to verify that it is a valid address. Opens the control channel - * and then negotiates the proxy connection with the server. + * and then negotiates the proxy connection with the server. Closes any existing SOCKS + * connection before proceeding. Also disables an HTTP proxy if it is using SOCKS as the proxy.   *   *   * @param host Socks server to connect to. @@ -185,43 +197,37 @@ S32 LLProxy::proxyHandshake(LLHost proxy)   */  S32 LLProxy::startSOCKSProxy(LLHost host)  { -	S32 status = SOCKS_OK; -  	if (host.isOk())  	{  		mTCPProxy = host;  	}  	else  	{ -		status = SOCKS_INVALID_HOST; +		return SOCKS_INVALID_HOST;  	} -	if (mProxyControlChannel && status == SOCKS_OK) -	{ -		tcp_close_channel(&mProxyControlChannel); -	} +	// Close any running SOCKS connection. +	stopSOCKSProxy(); -	if (status == SOCKS_OK) +	mProxyControlChannel = tcp_open_channel(mTCPProxy); +	if (!mProxyControlChannel)  	{ -		mProxyControlChannel = tcp_open_channel(mPool, mTCPProxy); -		if (!mProxyControlChannel) -		{ -			status = SOCKS_HOST_CONNECT_FAILED; -		} +		return SOCKS_HOST_CONNECT_FAILED;  	} -	if (status == SOCKS_OK) -	{ -		status = proxyHandshake(mTCPProxy); -	} -	if (status == SOCKS_OK) +	S32 status = proxyHandshake(mTCPProxy); + +	if (status != SOCKS_OK)  	{ -		sUDPProxyEnabled = true; +		// Shut down the proxy if any of the above steps failed. +		stopSOCKSProxy();  	}  	else  	{ -		stopSOCKSProxy(); +		// Connection was successful. +		sUDPProxyEnabled = true;  	} +  	return status;  } @@ -242,7 +248,7 @@ void LLProxy::stopSOCKSProxy()  	if (LLPROXY_SOCKS == getHTTPProxyType())  	{ -		void disableHTTPProxy(); +		disableHTTPProxy();  	}  	if (mProxyControlChannel) @@ -351,16 +357,6 @@ void LLProxy::disableHTTPProxy()  }  /** - * @brief Get the HTTP proxy address and port - */ -// -LLHost LLProxy::getHTTPProxy() const -{ -	LLMutexLock lock(&mProxyMutex); -	return mHTTPProxy; -} - -/**   * @brief Get the currently selected HTTP proxy type   */  LLHttpProxyType LLProxy::getHTTPProxyType() const @@ -441,21 +437,21 @@ void LLProxy::applyProxySettings(CURL* handle)  		// Now test again to verify that the proxy wasn't disabled between the first check and the lock.  		if (mHTTPProxyEnabled)  		{ -			check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str())); -			check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort())); +			LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str())); +			LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));  			if (mProxyType == LLPROXY_SOCKS)  			{ -				check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5)); +				LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));  				if (mAuthMethodSelected == METHOD_PASSWORD)  				{  					std::string auth_string = mSocksUsername + ":" + mSocksPassword; -					check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str())); +					LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));  				}  			}  			else  			{ -				check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP)); +				LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));  			}  		}  	} @@ -474,7 +470,7 @@ void LLProxy::applyProxySettings(CURL* handle)   * @param maxinlen		Maximum possible length of received data.  Short reads are allowed.   * @return 				Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received.   */ -static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen) +static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen)  {  	apr_socket_t* apr_socket = handle->getSocket();  	apr_status_t rv = APR_SUCCESS; @@ -523,13 +519,12 @@ static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outl   *   * Checks for a successful connection, and makes sure the connection is closed if it fails.   * - * @param pool		APR pool to pass into the LLSocket.   * @param host		The host to open the connection to.   * @return			The created socket.  Will evaluate as NULL if the connection is unsuccessful.   */ -static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, LLHost host) +static LLSocket::ptr_t tcp_open_channel(LLHost host)  { -	LLSocket::ptr_t socket = LLSocket::create(pool, LLSocket::STREAM_TCP); +	LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP);  	bool connected = socket->blockingConnect(host);  	if (!connected)  	{ @@ -542,7 +537,7 @@ static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, LLHost host)  /**   * @brief Close the socket.   * - * @param handle_ptr A pointer-to-pointer to avoid increasing the use count. + * @param handle_ptr The handle of the socket being closed. A pointer-to-pointer to avoid increasing the use count.   */  static void tcp_close_channel(LLSocket::ptr_t* handle_ptr)  { diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h index 29e7e28567..a919370540 100644 --- a/indra/llmessage/llproxy.h +++ b/indra/llmessage/llproxy.h @@ -36,7 +36,6 @@  #include <string>  // SOCKS error codes returned from the StartProxy method -  #define SOCKS_OK 0  #define SOCKS_CONNECT_ERROR (-1)  #define SOCKS_NOT_PERMITTED (-2) @@ -46,7 +45,6 @@  #define SOCKS_HOST_CONNECT_FAILED (-6)  #define SOCKS_INVALID_HOST (-7) -  #ifndef MAXHOSTNAMELEN  #define	MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */  #endif @@ -225,62 +223,71 @@ class LLProxy: public LLSingleton<LLProxy>  {  	LOG_CLASS(LLProxy);  public: -	// METHODS THAT DO NOT LOCK mProxyMutex! - +	/*########################################################################################### +	METHODS THAT DO NOT LOCK mProxyMutex! +	###########################################################################################*/ +	// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.  	LLProxy(); -	// static check for enabled status for UDP packets +	// Static check for enabled status for UDP packets. Call from main thread only.  	static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; } -	// check for enabled status for HTTP packets -	// mHTTPProxyEnabled is atomic, so no locking is required for thread safety. -	bool isHTTPProxyEnabled() const { return mHTTPProxyEnabled; } - -	// Get the UDP proxy address and port +	// Get the UDP proxy address and port. Call from main thread only.  	LLHost getUDPProxy() const { return mUDPProxy; } -	// Get the SOCKS 5 TCP control channel address and port -	LLHost getTCPProxy() const { return mTCPProxy; } +	/*########################################################################################### +	END OF NON-LOCKING METHODS +	###########################################################################################*/ -	// END OF NON-LOCKING METHODS +	/*########################################################################################### +	METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! +	###########################################################################################*/ +	// Destructor, closes open connections. Do not call directly, use cleanupClass(). +	~LLProxy(); -	// METHODS THAT DO LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! +	// Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be +	// destroyed before the call to apr_terminate. Call from main thread only. +	static void cleanupClass(); -	~LLProxy(); +	// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false. +	// Safe to call from any thread. +	void applyProxySettings(CURL* handle); +	void applyProxySettings(LLCurl::Easy* handle); +	void applyProxySettings(LLCurlEasyRequest* handle); -	// Start a connection to the SOCKS 5 proxy +	// Start a connection to the SOCKS 5 proxy. Call from main thread only.  	S32 startSOCKSProxy(LLHost host); -	// Disconnect and clean up any connection to the SOCKS 5 proxy +	// Disconnect and clean up any connection to the SOCKS 5 proxy. Call from main thread only.  	void stopSOCKSProxy(); -	// Delete LLProxy singleton, destroying the APR pool used by the control channel. -	static void cleanupClass(); - -	// Set up to use Password auth when connecting to the SOCKS proxy +	// Use Password auth when connecting to the SOCKS proxy. Call from main thread only.  	bool setAuthPassword(const std::string &username, const std::string &password); -	// Set up to use No Auth when connecting to the SOCKS proxy +	// Disable authentication when connecting to the SOCKS proxy. Call from main thread only.  	void setAuthNone(); -	// Get the currently selected auth method. -	LLSocks5AuthType getSelectedAuthMethod() const; - -	// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy -	// as specified in type +	// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy. +	// as specified in type. Call from main thread only.  	bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type);  	bool enableHTTPProxy(); -	// Stop proxying HTTP packets +	// Stop proxying HTTP packets. Call from main thread only.  	void disableHTTPProxy(); -	// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false. -	void applyProxySettings(CURL* handle); -	void applyProxySettings(LLCurl::Easy* handle); -	void applyProxySettings(LLCurlEasyRequest* handle); +	/*########################################################################################### +	END OF LOCKING METHODS +	###########################################################################################*/ +private: +	/*########################################################################################### +	METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! +	###########################################################################################*/ -	// Get the HTTP proxy address and port -	LLHost getHTTPProxy() const; +	// Perform a SOCKS 5 authentication and UDP association with the proxy server. +	S32 proxyHandshake(LLHost proxy); + +	// Get the currently selected auth method. +	LLSocks5AuthType getSelectedAuthMethod() const;  	// Get the currently selected HTTP proxy type  	LLHttpProxyType getHTTPProxyType() const; @@ -288,21 +295,21 @@ public:  	std::string getSocksPwd() const;  	std::string getSocksUser() const; -	// END OF LOCKING METHODS -private: -	// Open a communication channel to the SOCKS 5 proxy proxy, at port messagePort -	S32 proxyHandshake(LLHost proxy); +	/*########################################################################################### +	END OF LOCKING METHODS +	###########################################################################################*/  private: -	// Is the HTTP proxy enabled? -	// Safe to read in any thread, do not write directly, -	// use enableHTTPProxy() and disableHTTPProxy() instead. +	// Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly. +	// Instead use enableHTTPProxy() and disableHTTPProxy() instead.  	mutable LLAtomic32<bool> mHTTPProxyEnabled; -	// Mutex to protect shared members in non-main thread calls to applyProxySettings() +	// Mutex to protect shared members in non-main thread calls to applyProxySettings().  	mutable LLMutex mProxyMutex; -	// MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE! +	/*########################################################################################### +	MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE! +	###########################################################################################*/  	// Is the UDP proxy enabled?  	static bool sUDPProxyEnabled; @@ -315,12 +322,13 @@ private:  	// socket handle to proxy TCP control channel  	LLSocket::ptr_t mProxyControlChannel; -	// APR pool for the socket -	apr_pool_t* mPool; - -	// END OF UNSHARED MEMBERS +	/*########################################################################################### +	END OF UNSHARED MEMBERS +	###########################################################################################*/ -	// MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex! +	/*########################################################################################### +	MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex! +	###########################################################################################*/  	// HTTP proxy address and port  	LLHost mHTTPProxy; @@ -328,7 +336,7 @@ private:  	// Currently selected HTTP proxy type. Can be web or socks.  	LLHttpProxyType mProxyType; -	// SOCKS 5 auth method selected +	// SOCKS 5 selected authentication method.  	LLSocks5AuthType mAuthMethodSelected;  	// SOCKS 5 username @@ -336,7 +344,9 @@ private:  	// SOCKS 5 password  	std::string mSocksPassword; -	// END OF SHARED MEMBERS +	/*########################################################################################### +	END OF SHARED MEMBERS +	###########################################################################################*/  };  #endif diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index a8d2a0a224..89cfd66e1b 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -37,6 +37,7 @@  #include "llmemtype.h"  #include "llstl.h"  #include "llstat.h" +#include "llthread.h"  // These should not be enabled in production, but they can be  // intensely useful during development for finding certain kinds of @@ -162,14 +163,12 @@ struct ll_delete_apr_pollset_fd_client_data  /**   * LLPumpIO   */ -LLPumpIO::LLPumpIO(apr_pool_t* pool) : +LLPumpIO::LLPumpIO(void) :  	mState(LLPumpIO::NORMAL),  	mRebuildPollset(false),  	mPollset(NULL),  	mPollsetClientID(0),  	mNextLock(0), -	mPool(NULL), -	mCurrentPool(NULL),  	mCurrentPoolReallocCount(0),  	mChainsMutex(NULL),  	mCallbackMutex(NULL), @@ -178,21 +177,24 @@ LLPumpIO::LLPumpIO(apr_pool_t* pool) :  	mCurrentChain = mRunningChains.end();  	LLMemType m1(LLMemType::MTYPE_IO_PUMP); -	initialize(pool); +	initialize();  }  LLPumpIO::~LLPumpIO()  {  	LLMemType m1(LLMemType::MTYPE_IO_PUMP); -	cleanup(); -} - -bool LLPumpIO::prime(apr_pool_t* pool) -{ -	LLMemType m1(LLMemType::MTYPE_IO_PUMP); -	cleanup(); -	initialize(pool); -	return ((pool == NULL) ? false : true); +#if LL_THREADS_APR +	if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex); +	if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex); +#endif +	mChainsMutex = NULL; +	mCallbackMutex = NULL; +	if(mPollset) +	{ +//		lldebugs << "cleaning up pollset" << llendl; +		apr_pollset_destroy(mPollset); +		mPollset = NULL; +	}  }  bool LLPumpIO::addChain(const chain_t& chain, F32 timeout) @@ -352,8 +354,7 @@ bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll)  	{  		// each fd needs a pool to work with, so if one was  		// not specified, use this pool. -		// *FIX: Should it always be this pool? -		value.second.p = mPool; +		value.second.p = (*mCurrentChain).mDescriptorsPool->operator()();  	}  	value.second.client_data = new S32(++mPollsetClientID);  	(*mCurrentChain).mDescriptors.push_back(value); @@ -825,39 +826,15 @@ void LLPumpIO::control(LLPumpIO::EControl op)  	}  } -void LLPumpIO::initialize(apr_pool_t* pool) +void LLPumpIO::initialize(void)  {  	LLMemType m1(LLMemType::MTYPE_IO_PUMP); -	if(!pool) return; +	mPool.create();  #if LL_THREADS_APR  	// SJB: Windows defaults to NESTED and OSX defaults to UNNESTED, so use UNNESTED explicitly. -	apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, pool); -	apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, pool); -#endif -	mPool = pool; -} - -void LLPumpIO::cleanup() -{ -	LLMemType m1(LLMemType::MTYPE_IO_PUMP); -#if LL_THREADS_APR -	if(mChainsMutex) apr_thread_mutex_destroy(mChainsMutex); -	if(mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex); +	apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, mPool()); +	apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool());  #endif -	mChainsMutex = NULL; -	mCallbackMutex = NULL; -	if(mPollset) -	{ -//		lldebugs << "cleaning up pollset" << llendl; -		apr_pollset_destroy(mPollset); -		mPollset = NULL; -	} -	if(mCurrentPool) -	{ -		apr_pool_destroy(mCurrentPool); -		mCurrentPool = NULL; -	} -	mPool = NULL;  }  void LLPumpIO::rebuildPollset() @@ -885,21 +862,19 @@ void LLPumpIO::rebuildPollset()  		if(mCurrentPool  		   && (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT)))  		{ -			apr_pool_destroy(mCurrentPool); -			mCurrentPool = NULL; +			mCurrentPool.destroy();  			mCurrentPoolReallocCount = 0;  		}  		if(!mCurrentPool)  		{ -			apr_status_t status = apr_pool_create(&mCurrentPool, mPool); -			(void)ll_apr_warn_status(status); +			mCurrentPool.create(mPool);  		}  		// add all of the file descriptors  		run_it = mRunningChains.begin();  		LLChainInfo::conditionals_t::iterator fd_it;  		LLChainInfo::conditionals_t::iterator fd_end; -		apr_pollset_create(&mPollset, size, mCurrentPool, 0); +		apr_pollset_create(&mPollset, size, mCurrentPool(), 0);  		for(; run_it != run_end; ++run_it)  		{  			fd_it = (*run_it).mDescriptors.begin(); @@ -1157,7 +1132,8 @@ bool LLPumpIO::handleChainError(  LLPumpIO::LLChainInfo::LLChainInfo() :  	mInit(false),  	mLock(0), -	mEOS(false) +	mEOS(false), +	mDescriptorsPool(new LLAPRPool(LLThread::tldata().mRootPool))  {  	LLMemType m1(LLMemType::MTYPE_IO_PUMP);  	mTimer.setTimerExpirySec(DEFAULT_CHAIN_EXPIRY_SECS); diff --git a/indra/llmessage/llpumpio.h b/indra/llmessage/llpumpio.h index 9303c9d7fc..75c35ae7ab 100644 --- a/indra/llmessage/llpumpio.h +++ b/indra/llmessage/llpumpio.h @@ -30,11 +30,12 @@  #define LL_LLPUMPIO_H  #include <set> +#include <boost/shared_ptr.hpp>  #if LL_LINUX  // needed for PATH_MAX in APR.  #include <sys/param.h>  #endif -#include "apr_pools.h" +#include "llaprpool.h"  #include "llbuffer.h"  #include "llframetimer.h"  #include "lliopipe.h" @@ -58,9 +59,8 @@ extern const F32 NEVER_CHAIN_EXPIRY_SECS;   * <code>pump()</code> on a thread used for IO and call   * <code>respond()</code> on a thread that is expected to do higher   * level processing. You can call almost any other method from any - * thread - see notes for each method for details. In order for the - * threading abstraction to work, you need to call <code>prime()</code> - * with a valid apr pool. + * thread - see notes for each method for details. + *   * A pump instance manages much of the state for the pipe, including   * the list of pipes in the chain, the channel for each element in the   * chain, the buffer, and if any pipe has marked the stream or process @@ -79,7 +79,7 @@ public:  	/**  	 * @brief Constructor.  	 */ -	LLPumpIO(apr_pool_t* pool); +	LLPumpIO(void);  	/**  	 * @brief Destructor. @@ -87,17 +87,6 @@ public:  	~LLPumpIO();  	/** -	 * @brief Prepare this pump for usage. -	 * -	 * If you fail to call this method prior to use, the pump will -	 * try to work, but will not come with any thread locking -	 * mechanisms. -	 * @param pool The apr pool to use. -	 * @return Returns true if the pump is primed. -	 */ -	bool prime(apr_pool_t* pool); - -	/**  	 * @brief Typedef for having a chain of pipes.  	 */  	typedef std::vector<LLIOPipe::ptr_t> chain_t; @@ -368,6 +357,7 @@ protected:  		typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t;  		typedef std::vector<pipe_conditional_t> conditionals_t;  		conditionals_t mDescriptors; +		boost::shared_ptr<LLAPRPool> mDescriptorsPool;  	};  	// All the running chains & info @@ -386,9 +376,9 @@ protected:  	callbacks_t mPendingCallbacks;  	callbacks_t mCallbacks; -	// memory allocator for pollsets & mutexes. -	apr_pool_t* mPool; -	apr_pool_t* mCurrentPool; +	// Memory pool for pollsets & mutexes. +	LLAPRPool mPool; +	LLAPRPool mCurrentPool;  	S32 mCurrentPoolReallocCount;  #if LL_THREADS_APR @@ -400,8 +390,7 @@ protected:  #endif  protected: -	void initialize(apr_pool_t* pool); -	void cleanup(); +	void initialize();  	/**   	 * @brief Given the internal state of the chains, rebuild the pollset diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index d5400e4169..91a5a8ce2c 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -41,6 +41,7 @@  #include "llstring.h"  #include "apr_env.h"  #include "llapr.h" +#include "llscopedvolatileaprpool.h"  static const U32 HTTP_STATUS_PIPE_ERROR = 499;  /** @@ -211,26 +212,31 @@ void LLURLRequest::setCallback(LLURLRequestComplete* callback)  // is called with use_proxy = FALSE  void LLURLRequest::useProxy(bool use_proxy)  { -    static char *env_proxy; +    static std::string env_proxy; -    if (use_proxy && (env_proxy == NULL)) +    if (use_proxy && env_proxy.empty())      { -        apr_status_t status; -        LLAPRPool pool; -		status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool()); +		char* env_proxy_str; +        LLScopedVolatileAPRPool scoped_pool; +        apr_status_t status = apr_env_get(&env_proxy_str, "ALL_PROXY", scoped_pool);          if (status != APR_SUCCESS)          { -			status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool()); +			status = apr_env_get(&env_proxy_str, "http_proxy", scoped_pool);          }          if (status != APR_SUCCESS)          { -           use_proxy = FALSE; +            use_proxy = false;          } +		else +		{ +			// env_proxy_str is stored in the scoped_pool, so we have to make a copy. +			env_proxy = env_proxy_str; +		}      } -    LL_DEBUGS("Proxy") << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << LL_ENDL; +    LL_DEBUGS("Proxy") << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (!env_proxy.empty() ? env_proxy : "(null)") << LL_ENDL; -    if (env_proxy && use_proxy) +    if (use_proxy && !env_proxy.empty())      {  		mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy);      } diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index d0b0e178b8..7d21e35f96 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -97,8 +97,10 @@ std::string get_shared_secret();  class LLMessagePollInfo  {  public: +	LLMessagePollInfo(void) : mPool(LLThread::tldata().mRootPool) { }  	apr_socket_t *mAPRSocketp;  	apr_pollfd_t mPollFD; +	LLAPRPool mPool;  };  namespace @@ -287,20 +289,13 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port,  	}  //	LL_DEBUGS("Messaging") <<  << "*** port: " << mPort << llendl; -	// -	// Create the data structure that we can poll on -	// -	if (!gAPRPoolp) -	{ -		LL_ERRS("Messaging") << "No APR pool before message system initialization!" << llendl; -		ll_init_apr(); -	} +	mPollInfop = new LLMessagePollInfo; +  	apr_socket_t *aprSocketp = NULL; -	apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, gAPRPoolp); +	apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, mPollInfop->mPool()); -	mPollInfop = new LLMessagePollInfo;  	mPollInfop->mAPRSocketp = aprSocketp; -	mPollInfop->mPollFD.p = gAPRPoolp; +	mPollInfop->mPollFD.p = mPollInfop->mPool();  	mPollInfop->mPollFD.desc_type = APR_POLL_SOCKET;  	mPollInfop->mPollFD.reqevents = APR_POLLIN;  	mPollInfop->mPollFD.rtnevents = 0; diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h index 2aff90ca1e..23e1c791f4 100644 --- a/indra/llmessage/tests/networkio.h +++ b/indra/llmessage/tests/networkio.h @@ -30,7 +30,6 @@  #define LL_NETWORKIO_H  #include "llmemory.h"               // LLSingleton -#include "llapr.h"  #include "llares.h"  #include "llpumpio.h"  #include "llhttpclient.h" @@ -48,14 +47,8 @@ public:          mServicePump(NULL),          mDone(false)      { -        ll_init_apr(); -        if (! gAPRPoolp) -        { -            throw std::runtime_error("Can't initialize APR"); -        } -          // Create IO Pump to use for HTTP Requests. -        mServicePump = new LLPumpIO(gAPRPoolp); +        mServicePump = new LLPumpIO;          LLHTTPClient::setPump(*mServicePump);          if (ll_init_ares() == NULL || !gAres->isInitialized())          { diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index d081109acc..9cd3216ab2 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -1,1424 +1,1445 @@ -/**  - * @file llpluginclassmedia.cpp - * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class. - * - * @cond - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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$ - * @endcond - */ - -#include "linden_common.h" -#include "indra_constants.h" - -#include "llpluginclassmedia.h" -#include "llpluginmessageclasses.h" - -#include "llqtwebkit.h" - -static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256; - -static int nextPowerOf2( int value ) -{ -	int next_power_of_2 = 1; -	while ( next_power_of_2 < value ) -	{ -		next_power_of_2 <<= 1; -	} -	 -	return next_power_of_2; -} - -LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) -{ -	mOwner = owner; -	mPlugin = NULL; -	reset(); - -	//debug use -	mDeleteOK = true ; -} - - -LLPluginClassMedia::~LLPluginClassMedia() -{ -	llassert_always(mDeleteOK) ; -	reset(); -} - -bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug) -{	 -	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; -	LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL; -	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; -	 -	mPlugin = new LLPluginProcessParent(this); -	mPlugin->setSleepTime(mSleepTime); -	 -	// Queue up the media init message -- it will be sent after all the currently queued messages. -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); -	message.setValue("target", mTarget); -	sendMessage(message); -	 -	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug); - -	return true; -} - - -void LLPluginClassMedia::reset() -{ -	if(mPlugin != NULL) -	{ -		delete mPlugin; -		mPlugin = NULL; -	} - -	mTextureParamsReceived = false; -	mRequestedTextureDepth = 0; -	mRequestedTextureInternalFormat = 0; -	mRequestedTextureFormat = 0; -	mRequestedTextureType = 0; -	mRequestedTextureSwapBytes = false; -	mRequestedTextureCoordsOpenGL = false; -	mTextureSharedMemorySize = 0; -	mTextureSharedMemoryName.clear(); -	mDefaultMediaWidth = 0; -	mDefaultMediaHeight = 0; -	mNaturalMediaWidth = 0; -	mNaturalMediaHeight = 0; -	mSetMediaWidth = -1; -	mSetMediaHeight = -1; -	mRequestedMediaWidth = 0; -	mRequestedMediaHeight = 0; -	mRequestedTextureWidth = 0; -	mRequestedTextureHeight = 0; -	mFullMediaWidth = 0; -	mFullMediaHeight = 0; -	mTextureWidth = 0; -	mTextureHeight = 0; -	mMediaWidth = 0; -	mMediaHeight = 0; -	mDirtyRect = LLRect::null;	 -	mAutoScaleMedia = false; -	mRequestedVolume = 1.0f; -	mPriority = PRIORITY_NORMAL; -	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; -	mAllowDownsample = false; -	mPadding = 0; -	mLastMouseX = 0; -	mLastMouseY = 0; -	mStatus = LLPluginClassMediaOwner::MEDIA_NONE; -	mSleepTime = 1.0f / 100.0f; -	mCanCut = false; -	mCanCopy = false; -	mCanPaste = false; -	mMediaName.clear(); -	mMediaDescription.clear(); -	mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); -	 -	// media_browser class -	mNavigateURI.clear(); -	mNavigateResultCode = -1; -	mNavigateResultString.clear(); -	mHistoryBackAvailable = false; -	mHistoryForwardAvailable = false; -	mStatusText.clear(); -	mProgressPercent = 0;	 -	mClickURL.clear(); -	mClickNavType.clear(); -	mClickTarget.clear(); -	mClickUUID.clear(); -	mStatusCode = 0; -	 -	// media_time class -	mCurrentTime = 0.0f; -	mDuration = 0.0f; -	mCurrentRate = 0.0f; -	mLoadedDuration = 0.0f; -} - -void LLPluginClassMedia::idle(void) -{ -	if(mPlugin) -	{ -		mPlugin->idle(); -	} -	 -	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL)) -	{ -		// Can't process a size change at this time -	} -	else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight)) -	{ -		// Calculate the correct size for the media texture -		mRequestedTextureHeight = mRequestedMediaHeight; -		if(mPadding < 0) -		{ -			// negative values indicate the plugin wants a power of 2 -			mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth); -		} -		else -		{ -			mRequestedTextureWidth = mRequestedMediaWidth; -			 -			if(mPadding > 1) -			{ -				// Pad up to a multiple of the specified number of bytes per row -				int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth; -				int pad = rowbytes % mPadding; -				if(pad != 0) -				{ -					rowbytes += mPadding - pad; -				} -				 -				if(rowbytes % mRequestedTextureDepth == 0) -				{ -					mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; -				} -				else -				{ -					LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL; -				} -			} -		} - -		 -		// Size change has been requested but not initiated yet. -		size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; - -		// Add an extra line for padding, just in case. -		newsize += mRequestedTextureWidth * mRequestedTextureDepth; - -		if(newsize != mTextureSharedMemorySize) -		{ -			if(!mTextureSharedMemoryName.empty()) -			{ -				// Tell the plugin to remove the old memory segment -				mPlugin->removeSharedMemory(mTextureSharedMemoryName); -				mTextureSharedMemoryName.clear(); -			} -			 -			mTextureSharedMemorySize = newsize; -			mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); -			if(!mTextureSharedMemoryName.empty()) -			{ -				void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); -				 -				// clear texture memory to avoid random screen visual fuzz from uninitialized texture data -				memset( addr, 0x00, newsize ); -				 -				// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, -				// so it may not be worthwhile. -				// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); -			} -		} -		 -		// This is our local indicator that a change is in progress. -		mTextureWidth = -1; -		mTextureHeight = -1; -		mMediaWidth = -1; -		mMediaHeight = -1; - -		// This invalidates any existing dirty rect. -		resetDirty(); -		 -		// Send a size change message to the plugin -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); -			message.setValue("name", mTextureSharedMemoryName); -			message.setValueS32("width", mRequestedMediaWidth); -			message.setValueS32("height", mRequestedMediaHeight); -			message.setValueS32("texture_width", mRequestedTextureWidth); -			message.setValueS32("texture_height", mRequestedTextureHeight); -			message.setValueReal("background_r", mBackgroundColor.mV[VX]); -			message.setValueReal("background_g", mBackgroundColor.mV[VY]); -			message.setValueReal("background_b", mBackgroundColor.mV[VZ]); -			message.setValueReal("background_a", mBackgroundColor.mV[VW]); -			mPlugin->sendMessage(message);	// DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. -			 -			LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; -		} -	} -	 -	if(mPlugin && mPlugin->isRunning()) -	{ -		// Send queued messages -		while(!mSendQueue.empty()) -		{ -			LLPluginMessage message = mSendQueue.front(); -			mSendQueue.pop(); -			mPlugin->sendMessage(message); -		} -	} -} - -int LLPluginClassMedia::getTextureWidth() const -{ -	return nextPowerOf2(mTextureWidth); -} - -int LLPluginClassMedia::getTextureHeight() const -{ -	return nextPowerOf2(mTextureHeight); -} - -unsigned char* LLPluginClassMedia::getBitsData() -{ -	unsigned char *result = NULL; -	if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) -	{ -		result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); -	} -	return result; -} - -void LLPluginClassMedia::setSize(int width, int height) -{ -	if((width > 0) && (height > 0)) -	{ -		mSetMediaWidth = width; -		mSetMediaHeight = height; -	} -	else -	{ -		mSetMediaWidth = -1; -		mSetMediaHeight = -1; -	} - -	setSizeInternal(); -} - -void LLPluginClassMedia::setSizeInternal(void) -{ -	if((mSetMediaWidth > 0) && (mSetMediaHeight > 0)) -	{ -		mRequestedMediaWidth = mSetMediaWidth; -		mRequestedMediaHeight = mSetMediaHeight; -	} -	else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) -	{ -		mRequestedMediaWidth = mNaturalMediaWidth; -		mRequestedMediaHeight = mNaturalMediaHeight; -	} -	else -	{ -		mRequestedMediaWidth = mDefaultMediaWidth; -		mRequestedMediaHeight = mDefaultMediaHeight; -	} -	 -	// Save these for size/interest calculations -	mFullMediaWidth = mRequestedMediaWidth; -	mFullMediaHeight = mRequestedMediaHeight; -	 -	if(mAllowDownsample) -	{ -		switch(mPriority) -		{ -			case PRIORITY_SLIDESHOW: -			case PRIORITY_LOW: -				// Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit -				while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) -				{ -					mRequestedMediaWidth /= 2; -					mRequestedMediaHeight /= 2; -				} -			break; -			 -			default: -				// Don't adjust texture size -			break; -		} -	} -	 -	if(mAutoScaleMedia) -	{ -		mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); -		mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); -	} -	 -	if(mRequestedMediaWidth > 2048) -		mRequestedMediaWidth = 2048; - -	if(mRequestedMediaHeight > 2048) -		mRequestedMediaHeight = 2048; -} - -void LLPluginClassMedia::setAutoScale(bool auto_scale) -{ -	if(auto_scale != mAutoScaleMedia) -	{ -		mAutoScaleMedia = auto_scale; -		setSizeInternal(); -	} -} - -bool LLPluginClassMedia::textureValid(void) -{ -	if( -		!mTextureParamsReceived || -		mTextureWidth <= 0 || -		mTextureHeight <= 0 || -		mMediaWidth <= 0 || -		mMediaHeight <= 0 || -		mRequestedMediaWidth != mMediaWidth || -		mRequestedMediaHeight != mMediaHeight || -		getBitsData() == NULL -	)	 -		return false; -	 -	return true; -} - -bool LLPluginClassMedia::getDirty(LLRect *dirty_rect) -{ -	bool result = !mDirtyRect.isEmpty(); - -	if(dirty_rect != NULL) -	{ -		*dirty_rect = mDirtyRect; -	} - -	return result; -} - -void LLPluginClassMedia::resetDirty(void) -{ -	mDirtyRect = LLRect::null; -} - -std::string LLPluginClassMedia::translateModifiers(MASK modifiers) -{ -	std::string result; -	 -	 -	if(modifiers & MASK_CONTROL) -	{ -		result += "control|"; -	} - -	if(modifiers & MASK_ALT) -	{ -		result += "alt|"; -	} - -	if(modifiers & MASK_SHIFT) -	{ -		result += "shift|"; -	} - -	// TODO: should I deal with platform differences here or in callers? -	// TODO: how do we deal with the Mac "command" key? -/* -	if(modifiers & MASK_SOMETHING) -	{ -		result += "meta|"; -	} -*/	 -	return result; -} - -void LLPluginClassMedia::jsEnableObject( bool enable ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object"); -	message.setValueBoolean( "enable", enable ); -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location"); -	message.setValueReal( "x", x ); -	message.setValueReal( "y", y ); -	message.setValueReal( "z", z ); -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location"); -	message.setValueReal( "x", x ); -	message.setValueReal( "y", y ); -	message.setValueReal( "z", z ); -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentOrientationEvent( double angle ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation"); -	message.setValueReal( "angle", angle ); - -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language"); -	message.setValue( "language", language ); -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region"); -	message.setValue( "region", region ); -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity"); -	message.setValue( "maturity", maturity ); -	sendMessage( message ); -} - -void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers) -{ -	if(type == MOUSE_EVENT_MOVE) -	{ -		if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked()) -		{ -			// Don't queue up mouse move events that can't be delivered. -			return; -		} - -		if((x == mLastMouseX) && (y == mLastMouseY)) -		{ -			// Don't spam unnecessary mouse move events. -			return; -		} -		 -		mLastMouseX = x; -		mLastMouseY = y; -	} -	 -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); -	std::string temp; -	switch(type) -	{ -		case MOUSE_EVENT_DOWN:			temp = "down";			break; -		case MOUSE_EVENT_UP:			temp = "up";			break; -		case MOUSE_EVENT_MOVE:			temp = "move";			break; -		case MOUSE_EVENT_DOUBLE_CLICK:	temp = "double_click";	break; -	} -	message.setValue("event", temp); - -	message.setValueS32("button", button); - -	message.setValueS32("x", x); -	 -	// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. -	if(!mRequestedTextureCoordsOpenGL) -	{ -		// TODO: Should I use mMediaHeight or mRequestedMediaHeight here? -		y = mMediaHeight - y; -	} -	message.setValueS32("y", y); - -	message.setValue("modifiers", translateModifiers(modifiers)); -	 -	sendMessage(message); -} - -bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data) -{ -	bool result = true; -	 -	// FIXME: -	// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. -	// For now, return false for the ones the webkit plugin won't handle properly. -	 -	switch(key_code) -	{ -		case KEY_BACKSPACE:		 -		case KEY_TAB:			 -		case KEY_RETURN:		 -		case KEY_PAD_RETURN:	 -		case KEY_SHIFT:			 -		case KEY_CONTROL:		 -		case KEY_ALT:			 -		case KEY_CAPSLOCK:		 -		case KEY_ESCAPE:		 -		case KEY_PAGE_UP:		 -		case KEY_PAGE_DOWN:		 -		case KEY_END:			 -		case KEY_HOME:			 -		case KEY_LEFT:			 -		case KEY_UP:			 -		case KEY_RIGHT:			 -		case KEY_DOWN:			 -		case KEY_INSERT:		 -		case KEY_DELETE: -			// These will be handled		 -		break; -		 -		default: -			// regular ASCII characters will also be handled -			if(key_code >= KEY_SPECIAL) -			{ -				// Other "special" codes will not work properly. -				result = false; -			} -		break; -	} - -#if LL_DARWIN	 -	if(modifiers & MASK_ALT) -	{ -		// Option-key modified characters should be handled by the unicode input path instead of this one. -		result = false; -	} -#endif - -	if(result) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); -		std::string temp; -		switch(type) -		{ -			case KEY_EVENT_DOWN:			temp = "down";			break; -			case KEY_EVENT_UP:				temp = "up";			break; -			case KEY_EVENT_REPEAT:			temp = "repeat";		break; -		} -		message.setValue("event", temp); -		 -		message.setValueS32("key", key_code); - -		message.setValue("modifiers", translateModifiers(modifiers)); -		message.setValueLLSD("native_key_data", native_key_data); -		 -		sendMessage(message); -	} -		 -	return result; -} - -void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); - -	message.setValueS32("x", x); -	message.setValueS32("y", y); -	message.setValue("modifiers", translateModifiers(modifiers)); -	 -	sendMessage(message); -} -	 -bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); - -	message.setValue("text", text); -	message.setValue("modifiers", translateModifiers(modifiers)); -	message.setValueLLSD("native_key_data", native_key_data); -	 -	sendMessage(message); -	 -	return true; -} - -void LLPluginClassMedia::loadURI(const std::string &uri) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); - -	message.setValue("uri", uri); -	 -	sendMessage(message); -} - -const char* LLPluginClassMedia::priorityToString(EPriority priority) -{ -	const char* result = "UNKNOWN"; -	switch(priority) -	{ -		case PRIORITY_UNLOADED:		result = "unloaded";	break; -		case PRIORITY_STOPPED:		result = "stopped";		break; -		case PRIORITY_HIDDEN:		result = "hidden";		break; -		case PRIORITY_SLIDESHOW:	result = "slideshow";	break; -		case PRIORITY_LOW:			result = "low";			break; -		case PRIORITY_NORMAL:		result = "normal";		break; -		case PRIORITY_HIGH:			result = "high";		break; -	} -	 -	return result; -} - -void LLPluginClassMedia::setPriority(EPriority priority) -{ -	if(mPriority != priority) -	{ -		mPriority = priority; - -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); -		 -		std::string priority_string = priorityToString(priority); -		switch(priority) -		{ -			case PRIORITY_UNLOADED:	 -				mSleepTime = 1.0f; -			break; -			case PRIORITY_STOPPED:	 -				mSleepTime = 1.0f; -			break; -			case PRIORITY_HIDDEN:	 -				mSleepTime = 1.0f; -			break; -			case PRIORITY_SLIDESHOW: -				mSleepTime = 1.0f; -			break; -			case PRIORITY_LOW:		 -				mSleepTime = 1.0f / 25.0f; -			break; -			case PRIORITY_NORMAL:	 -				mSleepTime = 1.0f / 50.0f; -			break; -			case PRIORITY_HIGH:		 -				mSleepTime = 1.0f / 100.0f; -			break; -		} -		 -		message.setValue("priority", priority_string); - -		sendMessage(message); -		 -		if(mPlugin) -		{ -			mPlugin->setSleepTime(mSleepTime); -		} -		 -		LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; -		 -		// This may affect the calculated size, so recalculate it here. -		setSizeInternal(); -	} -} - -void LLPluginClassMedia::setLowPrioritySizeLimit(int size) -{ -	int power = nextPowerOf2(size); -	if(mLowPrioritySizeLimit != power) -	{ -		mLowPrioritySizeLimit = power; - -		// This may affect the calculated size, so recalculate it here. -		setSizeInternal(); -	} -} - -F64 LLPluginClassMedia::getCPUUsage() -{ -	F64 result = 0.0f; -	 -	if(mPlugin) -	{ -		result = mPlugin->getCPUUsage(); -	} -	 -	return result; -} - -void LLPluginClassMedia::sendPickFileResponse(const std::string &file) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response"); -	message.setValue("file", file); -	if(mPlugin && mPlugin->isBlocked()) -	{ -		// If the plugin sent a blocking pick-file request, the response should unblock it. -		message.setValueBoolean("blocking_response", true); -	} -	sendMessage(message); -} - -void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response"); -	message.setValueBoolean("ok", ok); -	message.setValue("username", username); -	message.setValue("password", password); -	if(mPlugin && mPlugin->isBlocked()) -	{ -		// If the plugin sent a blocking pick-file request, the response should unblock it. -		message.setValueBoolean("blocking_response", true); -	} -	sendMessage(message); -} - -void LLPluginClassMedia::cut() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); -	sendMessage(message); -} - -void LLPluginClassMedia::copy() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy"); -	sendMessage(message); -} - -void LLPluginClassMedia::paste() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste"); -	sendMessage(message); -} - -void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); -	message.setValue("path", user_data_path); -	sendMessage(message); -} - -void LLPluginClassMedia::setLanguageCode(const std::string &language_code) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code"); -	message.setValue("language", language_code); -	sendMessage(message); -} - -void LLPluginClassMedia::setPluginsEnabled(const bool enabled) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled"); -	message.setValueBoolean("enable", enabled); -	sendMessage(message); -} - -void LLPluginClassMedia::setJavascriptEnabled(const bool enabled) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled"); -	message.setValueBoolean("enable", enabled); -	sendMessage(message); -} - -void LLPluginClassMedia::setTarget(const std::string &target) -{ -	mTarget = target; -} - -/* virtual */  -void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) -{ -	std::string message_class = message.getClass(); -	 -	if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) -	{ -		std::string message_name = message.getName(); -		if(message_name == "texture_params") -		{ -			mRequestedTextureDepth = message.getValueS32("depth"); -			mRequestedTextureInternalFormat = message.getValueU32("internalformat"); -			mRequestedTextureFormat = message.getValueU32("format"); -			mRequestedTextureType = message.getValueU32("type"); -			mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes"); -			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");			 -			 -			// These two are optional, and will default to 0 if they're not specified. -			mDefaultMediaWidth = message.getValueS32("default_width"); -			mDefaultMediaHeight = message.getValueS32("default_height"); -			 -			mAllowDownsample = message.getValueBoolean("allow_downsample"); -			mPadding = message.getValueS32("padding"); - -			setSizeInternal(); -			 -			mTextureParamsReceived = true; -		} -		else if(message_name == "updated") -		{			 -			if(message.hasValue("left")) -			{ -				LLRect newDirtyRect; -				newDirtyRect.mLeft = message.getValueS32("left"); -				newDirtyRect.mTop = message.getValueS32("top"); -				newDirtyRect.mRight = message.getValueS32("right"); -				newDirtyRect.mBottom = message.getValueS32("bottom"); -							 -				// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion. -				// If they're backwards, swap them. -				if(newDirtyRect.mTop < newDirtyRect.mBottom) -				{ -					S32 temp = newDirtyRect.mTop; -					newDirtyRect.mTop = newDirtyRect.mBottom; -					newDirtyRect.mBottom = temp; -				} -				 -				if(mDirtyRect.isEmpty()) -				{ -					mDirtyRect = newDirtyRect; -				} -				else -				{ -					mDirtyRect.unionWith(newDirtyRect); -				} - -				LL_DEBUGS("Plugin") << "adjusted incoming rect is: ("  -					<< newDirtyRect.mLeft << ", " -					<< newDirtyRect.mTop << ", " -					<< newDirtyRect.mRight << ", " -					<< newDirtyRect.mBottom << "), new dirty rect is: (" -					<< mDirtyRect.mLeft << ", " -					<< mDirtyRect.mTop << ", " -					<< mDirtyRect.mRight << ", " -					<< mDirtyRect.mBottom << ")" -					<< LL_ENDL; -				 -				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED); -			}			 -			 - -			bool time_duration_updated = false; -			int previous_percent = mProgressPercent; - -			if(message.hasValue("current_time")) -			{ -				mCurrentTime = message.getValueReal("current_time"); -				time_duration_updated = true; -			} -			if(message.hasValue("duration")) -			{ -				mDuration = message.getValueReal("duration"); -				time_duration_updated = true; -			} - -			if(message.hasValue("current_rate")) -			{ -				mCurrentRate = message.getValueReal("current_rate"); -			} -			 -			if(message.hasValue("loaded_duration")) -			{ -				mLoadedDuration = message.getValueReal("loaded_duration"); -				time_duration_updated = true; -			} -			else -			{ -				// If the message doesn't contain a loaded_duration param, assume it's equal to duration -				mLoadedDuration = mDuration; -			} -			 -			// Calculate a percentage based on the loaded duration and total duration. -			if(mDuration != 0.0f)	// Don't divide by zero. -			{ -				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration); -			} - -			if(time_duration_updated) -			{ -				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED); -			} -			 -			if(previous_percent != mProgressPercent) -			{ -				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); -			} -		} -		else if(message_name == "media_status") -		{ -			std::string status = message.getValue("status"); -			 -			LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL; -			 -			if(status == "loading") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_LOADING; -			} -			else if(status == "loaded") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_LOADED; -			} -			else if(status == "error") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_ERROR; -			} -			else if(status == "playing") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING; -			} -			else if(status == "paused") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED; -			} -			else if(status == "done") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_DONE; -			} -			else -			{ -				// empty string or any unknown string -				mStatus = LLPluginClassMediaOwner::MEDIA_NONE; -			} -		} -		else if(message_name == "size_change_request") -		{ -			S32 width = message.getValueS32("width"); -			S32 height = message.getValueS32("height"); -			std::string name = message.getValue("name"); - -			// TODO: check that name matches? -			mNaturalMediaWidth = width; -			mNaturalMediaHeight = height; -			 -			setSizeInternal(); -		} -		else if(message_name == "size_change_response") -		{ -			std::string name = message.getValue("name"); -			 -			// TODO: check that name matches? -			 -			mTextureWidth = message.getValueS32("texture_width"); -			mTextureHeight = message.getValueS32("texture_height"); -			mMediaWidth = message.getValueS32("width"); -			mMediaHeight = message.getValueS32("height"); -			 -			// This invalidates any existing dirty rect. -			resetDirty(); -			 -			// TODO: should we verify that the plugin sent back the right values?   -			// Two size changes in a row may cause them to not match, due to queueing, etc. - -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED); -		} -		else if(message_name == "cursor_changed") -		{ -			mCursorName = message.getValue("name"); - -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED); -		} -		else if(message_name == "edit_state") -		{ -			if(message.hasValue("cut")) -			{ -				mCanCut = message.getValueBoolean("cut"); -			} -			if(message.hasValue("copy")) -			{ -				mCanCopy = message.getValueBoolean("copy"); -			} -			if(message.hasValue("paste")) -			{ -				mCanPaste = message.getValueBoolean("paste"); -			} -		} -		else if(message_name == "name_text") -		{ -			mMediaName = message.getValue("name"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); -		} -		else if(message_name == "pick_file") -		{ -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST); -		} -		else if(message_name == "auth_request") -		{ -			mAuthURL = message.getValue("url"); -			mAuthRealm = message.getValue("realm"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST); -		} -		else -		{ -			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; -		} -	} -	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) -	{ -		std::string message_name = message.getName(); -		if(message_name == "navigate_begin") -		{ -			mNavigateURI = message.getValue("uri"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN); -		} -		else if(message_name == "navigate_complete") -		{ -			mNavigateURI = message.getValue("uri"); -			mNavigateResultCode = message.getValueS32("result_code"); -			mNavigateResultString = message.getValue("result_string"); -			mHistoryBackAvailable = message.getValueBoolean("history_back_available"); -			mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); -			 -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE); -		} -		else if(message_name == "progress") -		{ -			mProgressPercent = message.getValueS32("percent"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); -		} -		else if(message_name == "status_text") -		{ -			mStatusText = message.getValue("status"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED); -		} -		else if(message_name == "location_changed") -		{ -			mLocation = message.getValue("uri"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED); -		} -		else if(message_name == "click_href") -		{ -			mClickURL = message.getValue("uri"); -			mClickTarget = message.getValue("target"); -			mClickUUID = message.getValue("uuid"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF); -		} -		else if(message_name == "click_nofollow") -		{ -			mClickURL = message.getValue("uri"); -			mClickNavType = message.getValue("nav_type"); -			mClickTarget.clear(); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW); -		} -		else if(message_name == "navigate_error_page") -		{ -			mStatusCode = message.getValueS32("status_code"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE); -		} -		else if(message_name == "cookie_set") -		{ -			if(mOwner) -			{ -				mOwner->handleCookieSet(this, message.getValue("cookie")); -			} -		} -		else if(message_name == "close_request") -		{ -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST); -		} -		else if(message_name == "geometry_change") -		{ -			mClickUUID = message.getValue("uuid"); -			mGeometryX = message.getValueS32("x"); -			mGeometryY = message.getValueS32("y"); -			mGeometryWidth = message.getValueS32("width"); -			mGeometryHeight = message.getValueS32("height"); -				 -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE); -		} -		else if(message_name == "link_hovered") -		{ -			// text is not currently used -- the tooltip hover text is taken from the "title". -			mHoverLink = message.getValue("link"); -			mHoverText = message.getValue("title"); -			// message.getValue("text"); -				 -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED); -		} -		else -		{ -			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; -		} -	} -	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) -	{ -		std::string message_name = message.getName(); - -		// This class hasn't defined any incoming messages yet. -//		if(message_name == "message_name") -//		{ -//		} -//		else  -		{ -			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; -		} -	} - -} - -/* virtual */  -void LLPluginClassMedia::pluginLaunchFailed() -{ -	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); -} - -/* virtual */  -void LLPluginClassMedia::pluginDied() -{ -	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); -} - -void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) -{ -	if(mOwner) -	{ -		mOwner->handleMediaEvent(this, event); -	} -} - -void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) -{ -	if(mPlugin && mPlugin->isRunning()) -	{ -		mPlugin->sendMessage(message); -	} -	else -	{ -		// The plugin isn't set up yet -- queue this message to be sent after initialization. -		mSendQueue.push(message); -	} -} - -//////////////////////////////////////////////////////////// -// MARK: media_browser class functions -bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) -{ -	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER); -	return !version.empty(); -} - -void LLPluginClassMedia::focus(bool focused) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); - -	message.setValueBoolean("focused", focused); -	 -	sendMessage(message); -} - -void LLPluginClassMedia::clear_cache() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache"); -	sendMessage(message); -} - -void LLPluginClassMedia::clear_cookies() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies"); -	sendMessage(message); -} - -void LLPluginClassMedia::set_cookies(const std::string &cookies) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies"); -	message.setValue("cookies", cookies);	 -	sendMessage(message); -} - -void LLPluginClassMedia::enable_cookies(bool enable) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies"); -	message.setValueBoolean("enable", enable); -	sendMessage(message); -} - -void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); - -	message.setValueBoolean("enable", enable); -	message.setValue("host", host); -	message.setValueS32("port", port); - -	sendMessage(message); -} - -void LLPluginClassMedia::browse_stop() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop"); -	sendMessage(message); -} - -void LLPluginClassMedia::browse_reload(bool ignore_cache) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); - -	message.setValueBoolean("ignore_cache", ignore_cache); -	 -	sendMessage(message); -} - -void LLPluginClassMedia::browse_forward() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward"); -	sendMessage(message); -} - -void LLPluginClassMedia::browse_back() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back"); -	sendMessage(message); -} - -void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); - -	message.setValue("user_agent", user_agent); - -	sendMessage(message); -} - -void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened"); - -	message.setValue("target", target); -	message.setValue("uuid", uuid); - -	sendMessage(message); -} - -void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed"); - -	message.setValue("uuid", uuid); - -	sendMessage(message); -} - -void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors"); -	message.setValueBoolean("ignore", ignore); -	sendMessage(message); -} - -void LLPluginClassMedia::addCertificateFilePath(const std::string& path) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path"); -	message.setValue("path", path); -	sendMessage(message); -} - -void LLPluginClassMedia::crashPlugin() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); - -	sendMessage(message); -} - -void LLPluginClassMedia::hangPlugin() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang"); - -	sendMessage(message); -} - - -//////////////////////////////////////////////////////////// -// MARK: media_time class functions -bool LLPluginClassMedia::pluginSupportsMediaTime(void) -{ -	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME); -	return !version.empty(); -} - -void LLPluginClassMedia::stop() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop"); -	sendMessage(message); -} - -void LLPluginClassMedia::start(float rate) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start"); - -	message.setValueReal("rate", rate); - -	sendMessage(message); -} - -void LLPluginClassMedia::pause() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause"); -	sendMessage(message); -} - -void LLPluginClassMedia::seek(float time) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); - -	message.setValueReal("time", time); -	 -	sendMessage(message); -} - -void LLPluginClassMedia::setLoop(bool loop) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop"); - -	message.setValueBoolean("loop", loop); - -	sendMessage(message); -} - -void LLPluginClassMedia::setVolume(float volume) -{ -	if(volume != mRequestedVolume) -	{ -		mRequestedVolume = volume; -		 -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); - -		message.setValueReal("volume", volume); -		 -		sendMessage(message); -	} -} - -float LLPluginClassMedia::getVolume() -{ -	return mRequestedVolume; -} - -void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history) -{ -	// Send URL history to plugin -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history"); -	message.setValueLLSD("history", url_history); -	sendMessage(message); - -	LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; -} - +/** 
 + * @file llpluginclassmedia.cpp
 + * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
 + *
 + * @cond
 + * $LicenseInfo:firstyear=2008&license=viewerlgpl$
 + * Second Life Viewer Source Code
 + * Copyright (C) 2010, 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$
 + * @endcond
 + */
 +
 +#include "linden_common.h"
 +#include "indra_constants.h"
 +
 +#include "llpluginclassmedia.h"
 +#include "llpluginmessageclasses.h"
 +
 +#include "llqtwebkit.h"
 +
 +static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256;
 +
 +static int nextPowerOf2( int value )
 +{
 +	int next_power_of_2 = 1;
 +	while ( next_power_of_2 < value )
 +	{
 +		next_power_of_2 <<= 1;
 +	}
 +	
 +	return next_power_of_2;
 +}
 +
 +LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
 +{
 +	mOwner = owner;
 +	mPlugin = NULL;
 +	reset();
 +
 +	//debug use
 +	mDeleteOK = true ;
 +}
 +
 +
 +LLPluginClassMedia::~LLPluginClassMedia()
 +{
 +	llassert_always(mDeleteOK) ;
 +	reset();
 +}
 +
 +bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
 +{	
 +	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
 +	LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
 +	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
 +	
 +	mPlugin = new LLPluginProcessParent(this);
 +	mPlugin->setSleepTime(mSleepTime);
 +	
 +	// Queue up the media init message -- it will be sent after all the currently queued messages.
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
 +	message.setValue("target", mTarget);
 +	sendMessage(message);
 +	
 +	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
 +
 +	return true;
 +}
 +
 +
 +void LLPluginClassMedia::reset()
 +{
 +	if(mPlugin != NULL)
 +	{
 +		delete mPlugin;
 +		mPlugin = NULL;
 +	}
 +
 +	mTextureParamsReceived = false;
 +	mRequestedTextureDepth = 0;
 +	mRequestedTextureInternalFormat = 0;
 +	mRequestedTextureFormat = 0;
 +	mRequestedTextureType = 0;
 +	mRequestedTextureSwapBytes = false;
 +	mRequestedTextureCoordsOpenGL = false;
 +	mTextureSharedMemorySize = 0;
 +	mTextureSharedMemoryName.clear();
 +	mDefaultMediaWidth = 0;
 +	mDefaultMediaHeight = 0;
 +	mNaturalMediaWidth = 0;
 +	mNaturalMediaHeight = 0;
 +	mSetMediaWidth = -1;
 +	mSetMediaHeight = -1;
 +	mRequestedMediaWidth = 0;
 +	mRequestedMediaHeight = 0;
 +	mRequestedTextureWidth = 0;
 +	mRequestedTextureHeight = 0;
 +	mFullMediaWidth = 0;
 +	mFullMediaHeight = 0;
 +	mTextureWidth = 0;
 +	mTextureHeight = 0;
 +	mMediaWidth = 0;
 +	mMediaHeight = 0;
 +	mDirtyRect = LLRect::null;	
 +	mAutoScaleMedia = false;
 +	mRequestedVolume = 1.0f;
 +	mPriority = PRIORITY_NORMAL;
 +	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
 +	mAllowDownsample = false;
 +	mPadding = 0;
 +	mLastMouseX = 0;
 +	mLastMouseY = 0;
 +	mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
 +	mSleepTime = 1.0f / 100.0f;
 +	mCanCut = false;
 +	mCanCopy = false;
 +	mCanPaste = false;
 +	mMediaName.clear();
 +	mMediaDescription.clear();
 +	mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
 +	
 +	// media_browser class
 +	mNavigateURI.clear();
 +	mNavigateResultCode = -1;
 +	mNavigateResultString.clear();
 +	mHistoryBackAvailable = false;
 +	mHistoryForwardAvailable = false;
 +	mStatusText.clear();
 +	mProgressPercent = 0;	
 +	mClickURL.clear();
 +	mClickNavType.clear();
 +	mClickTarget.clear();
 +	mClickUUID.clear();
 +	mStatusCode = 0;
 +	
 +	// media_time class
 +	mCurrentTime = 0.0f;
 +	mDuration = 0.0f;
 +	mCurrentRate = 0.0f;
 +	mLoadedDuration = 0.0f;
 +}
 +
 +void LLPluginClassMedia::idle(void)
 +{
 +	if(mPlugin)
 +	{
 +		mPlugin->idle();
 +	}
 +	
 +	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
 +	{
 +		// Can't process a size change at this time
 +	}
 +	else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight))
 +	{
 +		// Calculate the correct size for the media texture
 +		mRequestedTextureHeight = mRequestedMediaHeight;
 +		if(mPadding < 0)
 +		{
 +			// negative values indicate the plugin wants a power of 2
 +			mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth);
 +		}
 +		else
 +		{
 +			mRequestedTextureWidth = mRequestedMediaWidth;
 +			
 +			if(mPadding > 1)
 +			{
 +				// Pad up to a multiple of the specified number of bytes per row
 +				int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth;
 +				int pad = rowbytes % mPadding;
 +				if(pad != 0)
 +				{
 +					rowbytes += mPadding - pad;
 +				}
 +				
 +				if(rowbytes % mRequestedTextureDepth == 0)
 +				{
 +					mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
 +				}
 +				else
 +				{
 +					LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL;
 +				}
 +			}
 +		}
 +
 +		
 +		// Size change has been requested but not initiated yet.
 +		size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
 +
 +		// Add an extra line for padding, just in case.
 +		newsize += mRequestedTextureWidth * mRequestedTextureDepth;
 +
 +		if(newsize != mTextureSharedMemorySize)
 +		{
 +			if(!mTextureSharedMemoryName.empty())
 +			{
 +				// Tell the plugin to remove the old memory segment
 +				mPlugin->removeSharedMemory(mTextureSharedMemoryName);
 +				mTextureSharedMemoryName.clear();
 +			}
 +			
 +			mTextureSharedMemorySize = newsize;
 +			mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
 +			if(!mTextureSharedMemoryName.empty())
 +			{
 +				void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
 +				
 +				// clear texture memory to avoid random screen visual fuzz from uninitialized texture data
 +				memset( addr, 0x00, newsize );
 +				
 +				// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
 +				// so it may not be worthwhile.
 +				// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
 +			}
 +		}
 +		
 +		// This is our local indicator that a change is in progress.
 +		mTextureWidth = -1;
 +		mTextureHeight = -1;
 +		mMediaWidth = -1;
 +		mMediaHeight = -1;
 +
 +		// This invalidates any existing dirty rect.
 +		resetDirty();
 +		
 +		// Send a size change message to the plugin
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
 +			message.setValue("name", mTextureSharedMemoryName);
 +			message.setValueS32("width", mRequestedMediaWidth);
 +			message.setValueS32("height", mRequestedMediaHeight);
 +			message.setValueS32("texture_width", mRequestedTextureWidth);
 +			message.setValueS32("texture_height", mRequestedTextureHeight);
 +			message.setValueReal("background_r", mBackgroundColor.mV[VX]);
 +			message.setValueReal("background_g", mBackgroundColor.mV[VY]);
 +			message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
 +			message.setValueReal("background_a", mBackgroundColor.mV[VW]);
 +			mPlugin->sendMessage(message);	// DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
 +			
 +			LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
 +		}
 +	}
 +	
 +	if(mPlugin && mPlugin->isRunning())
 +	{
 +		// Send queued messages
 +		while(!mSendQueue.empty())
 +		{
 +			LLPluginMessage message = mSendQueue.front();
 +			mSendQueue.pop();
 +			mPlugin->sendMessage(message);
 +		}
 +	}
 +}
 +
 +int LLPluginClassMedia::getTextureWidth() const
 +{
 +	return nextPowerOf2(mTextureWidth);
 +}
 +
 +int LLPluginClassMedia::getTextureHeight() const
 +{
 +	return nextPowerOf2(mTextureHeight);
 +}
 +
 +unsigned char* LLPluginClassMedia::getBitsData()
 +{
 +	unsigned char *result = NULL;
 +	if((mPlugin != NULL) && !mTextureSharedMemoryName.empty())
 +	{
 +		result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
 +	}
 +	return result;
 +}
 +
 +void LLPluginClassMedia::setSize(int width, int height)
 +{
 +	if((width > 0) && (height > 0))
 +	{
 +		mSetMediaWidth = width;
 +		mSetMediaHeight = height;
 +	}
 +	else
 +	{
 +		mSetMediaWidth = -1;
 +		mSetMediaHeight = -1;
 +	}
 +
 +	setSizeInternal();
 +}
 +
 +void LLPluginClassMedia::setSizeInternal(void)
 +{
 +	if((mSetMediaWidth > 0) && (mSetMediaHeight > 0))
 +	{
 +		mRequestedMediaWidth = mSetMediaWidth;
 +		mRequestedMediaHeight = mSetMediaHeight;
 +	}
 +	else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0))
 +	{
 +		mRequestedMediaWidth = mNaturalMediaWidth;
 +		mRequestedMediaHeight = mNaturalMediaHeight;
 +	}
 +	else
 +	{
 +		mRequestedMediaWidth = mDefaultMediaWidth;
 +		mRequestedMediaHeight = mDefaultMediaHeight;
 +	}
 +	
 +	// Save these for size/interest calculations
 +	mFullMediaWidth = mRequestedMediaWidth;
 +	mFullMediaHeight = mRequestedMediaHeight;
 +	
 +	if(mAllowDownsample)
 +	{
 +		switch(mPriority)
 +		{
 +			case PRIORITY_SLIDESHOW:
 +			case PRIORITY_LOW:
 +				// Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit
 +				while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit))
 +				{
 +					mRequestedMediaWidth /= 2;
 +					mRequestedMediaHeight /= 2;
 +				}
 +			break;
 +			
 +			default:
 +				// Don't adjust texture size
 +			break;
 +		}
 +	}
 +	
 +	if(mAutoScaleMedia)
 +	{
 +		mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
 +		mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
 +	}
 +	
 +	if(mRequestedMediaWidth > 2048)
 +		mRequestedMediaWidth = 2048;
 +
 +	if(mRequestedMediaHeight > 2048)
 +		mRequestedMediaHeight = 2048;
 +}
 +
 +void LLPluginClassMedia::setAutoScale(bool auto_scale)
 +{
 +	if(auto_scale != mAutoScaleMedia)
 +	{
 +		mAutoScaleMedia = auto_scale;
 +		setSizeInternal();
 +	}
 +}
 +
 +bool LLPluginClassMedia::textureValid(void)
 +{
 +	if(
 +		!mTextureParamsReceived ||
 +		mTextureWidth <= 0 ||
 +		mTextureHeight <= 0 ||
 +		mMediaWidth <= 0 ||
 +		mMediaHeight <= 0 ||
 +		mRequestedMediaWidth != mMediaWidth ||
 +		mRequestedMediaHeight != mMediaHeight ||
 +		getBitsData() == NULL
 +	)	
 +		return false;
 +	
 +	return true;
 +}
 +
 +bool LLPluginClassMedia::getDirty(LLRect *dirty_rect)
 +{
 +	bool result = !mDirtyRect.isEmpty();
 +
 +	if(dirty_rect != NULL)
 +	{
 +		*dirty_rect = mDirtyRect;
 +	}
 +
 +	return result;
 +}
 +
 +void LLPluginClassMedia::resetDirty(void)
 +{
 +	mDirtyRect = LLRect::null;
 +}
 +
 +std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
 +{
 +	std::string result;
 +	
 +	
 +	if(modifiers & MASK_CONTROL)
 +	{
 +		result += "control|";
 +	}
 +
 +	if(modifiers & MASK_ALT)
 +	{
 +		result += "alt|";
 +	}
 +
 +	if(modifiers & MASK_SHIFT)
 +	{
 +		result += "shift|";
 +	}
 +
 +	// TODO: should I deal with platform differences here or in callers?
 +	// TODO: how do we deal with the Mac "command" key?
 +/*
 +	if(modifiers & MASK_SOMETHING)
 +	{
 +		result += "meta|";
 +	}
 +*/	
 +	return result;
 +}
 +
 +void LLPluginClassMedia::jsEnableObject( bool enable )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object");
 +	message.setValueBoolean( "enable", enable );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location");
 +	message.setValueReal( "x", x );
 +	message.setValueReal( "y", y );
 +	message.setValueReal( "z", z );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location");
 +	message.setValueReal( "x", x );
 +	message.setValueReal( "y", y );
 +	message.setValueReal( "z", z );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentOrientationEvent( double angle )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation");
 +	message.setValueReal( "angle", angle );
 +
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language");
 +	message.setValue( "language", language );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region");
 +	message.setValue( "region", region );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity");
 +	message.setValue( "maturity", maturity );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers)
 +{
 +	if(type == MOUSE_EVENT_MOVE)
 +	{
 +		if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked())
 +		{
 +			// Don't queue up mouse move events that can't be delivered.
 +			return;
 +		}
 +
 +		if((x == mLastMouseX) && (y == mLastMouseY))
 +		{
 +			// Don't spam unnecessary mouse move events.
 +			return;
 +		}
 +		
 +		mLastMouseX = x;
 +		mLastMouseY = y;
 +	}
 +	
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
 +	std::string temp;
 +	switch(type)
 +	{
 +		case MOUSE_EVENT_DOWN:			temp = "down";			break;
 +		case MOUSE_EVENT_UP:			temp = "up";			break;
 +		case MOUSE_EVENT_MOVE:			temp = "move";			break;
 +		case MOUSE_EVENT_DOUBLE_CLICK:	temp = "double_click";	break;
 +	}
 +	message.setValue("event", temp);
 +
 +	message.setValueS32("button", button);
 +
 +	message.setValueS32("x", x);
 +	
 +	// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
 +	if(!mRequestedTextureCoordsOpenGL)
 +	{
 +		// TODO: Should I use mMediaHeight or mRequestedMediaHeight here?
 +		y = mMediaHeight - y;
 +	}
 +	message.setValueS32("y", y);
 +
 +	message.setValue("modifiers", translateModifiers(modifiers));
 +	
 +	sendMessage(message);
 +}
 +
 +bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
 +{
 +	bool result = true;
 +	
 +	// FIXME:
 +	// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
 +	// For now, return false for the ones the webkit plugin won't handle properly.
 +	
 +	switch(key_code)
 +	{
 +		case KEY_BACKSPACE:		
 +		case KEY_TAB:			
 +		case KEY_RETURN:		
 +		case KEY_PAD_RETURN:	
 +		case KEY_SHIFT:			
 +		case KEY_CONTROL:		
 +		case KEY_ALT:			
 +		case KEY_CAPSLOCK:		
 +		case KEY_ESCAPE:		
 +		case KEY_PAGE_UP:		
 +		case KEY_PAGE_DOWN:		
 +		case KEY_END:			
 +		case KEY_HOME:			
 +		case KEY_LEFT:			
 +		case KEY_UP:			
 +		case KEY_RIGHT:			
 +		case KEY_DOWN:			
 +		case KEY_INSERT:		
 +		case KEY_DELETE:
 +			// These will be handled		
 +		break;
 +		
 +		default:
 +			// regular ASCII characters will also be handled
 +			if(key_code >= KEY_SPECIAL)
 +			{
 +				// Other "special" codes will not work properly.
 +				result = false;
 +			}
 +		break;
 +	}
 +
 +#if LL_DARWIN	
 +	if(modifiers & MASK_ALT)
 +	{
 +		// Option-key modified characters should be handled by the unicode input path instead of this one.
 +		result = false;
 +	}
 +#endif
 +
 +	if(result)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event");
 +		std::string temp;
 +		switch(type)
 +		{
 +			case KEY_EVENT_DOWN:			temp = "down";			break;
 +			case KEY_EVENT_UP:				temp = "up";			break;
 +			case KEY_EVENT_REPEAT:			temp = "repeat";		break;
 +		}
 +		message.setValue("event", temp);
 +		
 +		message.setValueS32("key", key_code);
 +
 +		message.setValue("modifiers", translateModifiers(modifiers));
 +		message.setValueLLSD("native_key_data", native_key_data);
 +		
 +		sendMessage(message);
 +	}
 +		
 +	return result;
 +}
 +
 +void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event");
 +
 +	message.setValueS32("x", x);
 +	message.setValueS32("y", y);
 +	message.setValue("modifiers", translateModifiers(modifiers));
 +	
 +	sendMessage(message);
 +}
 +	
 +bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
 +
 +	message.setValue("text", text);
 +	message.setValue("modifiers", translateModifiers(modifiers));
 +	message.setValueLLSD("native_key_data", native_key_data);
 +	
 +	sendMessage(message);
 +	
 +	return true;
 +}
 +
 +void LLPluginClassMedia::loadURI(const std::string &uri)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
 +
 +	message.setValue("uri", uri);
 +	
 +	sendMessage(message);
 +}
 +
 +const char* LLPluginClassMedia::priorityToString(EPriority priority)
 +{
 +	const char* result = "UNKNOWN";
 +	switch(priority)
 +	{
 +		case PRIORITY_UNLOADED:		result = "unloaded";	break;
 +		case PRIORITY_STOPPED:		result = "stopped";		break;
 +		case PRIORITY_HIDDEN:		result = "hidden";		break;
 +		case PRIORITY_SLIDESHOW:	result = "slideshow";	break;
 +		case PRIORITY_LOW:			result = "low";			break;
 +		case PRIORITY_NORMAL:		result = "normal";		break;
 +		case PRIORITY_HIGH:			result = "high";		break;
 +	}
 +	
 +	return result;
 +}
 +
 +void LLPluginClassMedia::setPriority(EPriority priority)
 +{
 +	if(mPriority != priority)
 +	{
 +		mPriority = priority;
 +
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
 +		
 +		std::string priority_string = priorityToString(priority);
 +		switch(priority)
 +		{
 +			case PRIORITY_UNLOADED:	
 +				mSleepTime = 1.0f;
 +			break;
 +			case PRIORITY_STOPPED:	
 +				mSleepTime = 1.0f;
 +			break;
 +			case PRIORITY_HIDDEN:	
 +				mSleepTime = 1.0f;
 +			break;
 +			case PRIORITY_SLIDESHOW:
 +				mSleepTime = 1.0f;
 +			break;
 +			case PRIORITY_LOW:		
 +				mSleepTime = 1.0f / 25.0f;
 +			break;
 +			case PRIORITY_NORMAL:	
 +				mSleepTime = 1.0f / 50.0f;
 +			break;
 +			case PRIORITY_HIGH:		
 +				mSleepTime = 1.0f / 100.0f;
 +			break;
 +		}
 +		
 +		message.setValue("priority", priority_string);
 +
 +		sendMessage(message);
 +		
 +		if(mPlugin)
 +		{
 +			mPlugin->setSleepTime(mSleepTime);
 +		}
 +		
 +		LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
 +		
 +		// This may affect the calculated size, so recalculate it here.
 +		setSizeInternal();
 +	}
 +}
 +
 +void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
 +{
 +	int power = nextPowerOf2(size);
 +	if(mLowPrioritySizeLimit != power)
 +	{
 +		mLowPrioritySizeLimit = power;
 +
 +		// This may affect the calculated size, so recalculate it here.
 +		setSizeInternal();
 +	}
 +}
 +
 +F64 LLPluginClassMedia::getCPUUsage()
 +{
 +	F64 result = 0.0f;
 +	
 +	if(mPlugin)
 +	{
 +		result = mPlugin->getCPUUsage();
 +	}
 +	
 +	return result;
 +}
 +
 +void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
 +	message.setValue("file", file);
 +	if(mPlugin && mPlugin->isBlocked())
 +	{
 +		// If the plugin sent a blocking pick-file request, the response should unblock it.
 +		message.setValueBoolean("blocking_response", true);
 +	}
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response");
 +	message.setValueBoolean("ok", ok);
 +	message.setValue("username", username);
 +	message.setValue("password", password);
 +	if(mPlugin && mPlugin->isBlocked())
 +	{
 +		// If the plugin sent a blocking pick-file request, the response should unblock it.
 +		message.setValueBoolean("blocking_response", true);
 +	}
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::cut()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::copy()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::paste()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
 +	message.setValue("path", user_data_path);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code");
 +	message.setValue("language", language_code);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
 +	message.setValueBoolean("enable", enabled);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
 +	message.setValueBoolean("enable", enabled);
 +	sendMessage(message);
 +}
 +
 +
 +void LLPluginClassMedia::enableMediaPluginDebugging( bool enable )
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "enable_media_plugin_debugging");
 +	message.setValueBoolean( "enable", enable );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::setTarget(const std::string &target)
 +{
 +	mTarget = target;
 +}
 +
 +/* virtual */ 
 +void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 +{
 +	std::string message_class = message.getClass();
 +	
 +	if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
 +	{
 +		std::string message_name = message.getName();
 +		if(message_name == "texture_params")
 +		{
 +			mRequestedTextureDepth = message.getValueS32("depth");
 +			mRequestedTextureInternalFormat = message.getValueU32("internalformat");
 +			mRequestedTextureFormat = message.getValueU32("format");
 +			mRequestedTextureType = message.getValueU32("type");
 +			mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
 +			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");			
 +			
 +			// These two are optional, and will default to 0 if they're not specified.
 +			mDefaultMediaWidth = message.getValueS32("default_width");
 +			mDefaultMediaHeight = message.getValueS32("default_height");
 +			
 +			mAllowDownsample = message.getValueBoolean("allow_downsample");
 +			mPadding = message.getValueS32("padding");
 +
 +			setSizeInternal();
 +			
 +			mTextureParamsReceived = true;
 +		}
 +		else if(message_name == "updated")
 +		{			
 +			if(message.hasValue("left"))
 +			{
 +				LLRect newDirtyRect;
 +				newDirtyRect.mLeft = message.getValueS32("left");
 +				newDirtyRect.mTop = message.getValueS32("top");
 +				newDirtyRect.mRight = message.getValueS32("right");
 +				newDirtyRect.mBottom = message.getValueS32("bottom");
 +							
 +				// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
 +				// If they're backwards, swap them.
 +				if(newDirtyRect.mTop < newDirtyRect.mBottom)
 +				{
 +					S32 temp = newDirtyRect.mTop;
 +					newDirtyRect.mTop = newDirtyRect.mBottom;
 +					newDirtyRect.mBottom = temp;
 +				}
 +				
 +				if(mDirtyRect.isEmpty())
 +				{
 +					mDirtyRect = newDirtyRect;
 +				}
 +				else
 +				{
 +					mDirtyRect.unionWith(newDirtyRect);
 +				}
 +
 +				LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" 
 +					<< newDirtyRect.mLeft << ", "
 +					<< newDirtyRect.mTop << ", "
 +					<< newDirtyRect.mRight << ", "
 +					<< newDirtyRect.mBottom << "), new dirty rect is: ("
 +					<< mDirtyRect.mLeft << ", "
 +					<< mDirtyRect.mTop << ", "
 +					<< mDirtyRect.mRight << ", "
 +					<< mDirtyRect.mBottom << ")"
 +					<< LL_ENDL;
 +				
 +				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
 +			}			
 +			
 +
 +			bool time_duration_updated = false;
 +			int previous_percent = mProgressPercent;
 +
 +			if(message.hasValue("current_time"))
 +			{
 +				mCurrentTime = message.getValueReal("current_time");
 +				time_duration_updated = true;
 +			}
 +			if(message.hasValue("duration"))
 +			{
 +				mDuration = message.getValueReal("duration");
 +				time_duration_updated = true;
 +			}
 +
 +			if(message.hasValue("current_rate"))
 +			{
 +				mCurrentRate = message.getValueReal("current_rate");
 +			}
 +			
 +			if(message.hasValue("loaded_duration"))
 +			{
 +				mLoadedDuration = message.getValueReal("loaded_duration");
 +				time_duration_updated = true;
 +			}
 +			else
 +			{
 +				// If the message doesn't contain a loaded_duration param, assume it's equal to duration
 +				mLoadedDuration = mDuration;
 +			}
 +			
 +			// Calculate a percentage based on the loaded duration and total duration.
 +			if(mDuration != 0.0f)	// Don't divide by zero.
 +			{
 +				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration);
 +			}
 +
 +			if(time_duration_updated)
 +			{
 +				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
 +			}
 +			
 +			if(previous_percent != mProgressPercent)
 +			{
 +				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
 +			}
 +		}
 +		else if(message_name == "media_status")
 +		{
 +			std::string status = message.getValue("status");
 +			
 +			LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
 +			
 +			if(status == "loading")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
 +			}
 +			else if(status == "loaded")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_LOADED;
 +			}
 +			else if(status == "error")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_ERROR;
 +			}
 +			else if(status == "playing")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING;
 +			}
 +			else if(status == "paused")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED;
 +			}
 +			else if(status == "done")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_DONE;
 +			}
 +			else
 +			{
 +				// empty string or any unknown string
 +				mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
 +			}
 +		}
 +		else if(message_name == "size_change_request")
 +		{
 +			S32 width = message.getValueS32("width");
 +			S32 height = message.getValueS32("height");
 +			std::string name = message.getValue("name");
 +
 +			// TODO: check that name matches?
 +			mNaturalMediaWidth = width;
 +			mNaturalMediaHeight = height;
 +			
 +			setSizeInternal();
 +		}
 +		else if(message_name == "size_change_response")
 +		{
 +			std::string name = message.getValue("name");
 +			
 +			// TODO: check that name matches?
 +			
 +			mTextureWidth = message.getValueS32("texture_width");
 +			mTextureHeight = message.getValueS32("texture_height");
 +			mMediaWidth = message.getValueS32("width");
 +			mMediaHeight = message.getValueS32("height");
 +			
 +			// This invalidates any existing dirty rect.
 +			resetDirty();
 +			
 +			// TODO: should we verify that the plugin sent back the right values?  
 +			// Two size changes in a row may cause them to not match, due to queueing, etc.
 +
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
 +		}
 +		else if(message_name == "cursor_changed")
 +		{
 +			mCursorName = message.getValue("name");
 +
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED);
 +		}
 +		else if(message_name == "edit_state")
 +		{
 +			if(message.hasValue("cut"))
 +			{
 +				mCanCut = message.getValueBoolean("cut");
 +			}
 +			if(message.hasValue("copy"))
 +			{
 +				mCanCopy = message.getValueBoolean("copy");
 +			}
 +			if(message.hasValue("paste"))
 +			{
 +				mCanPaste = message.getValueBoolean("paste");
 +			}
 +		}
 +		else if(message_name == "name_text")
 +		{
 +			mMediaName = message.getValue("name");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
 +		}
 +		else if(message_name == "pick_file")
 +		{
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
 +		}
 +		else if(message_name == "auth_request")
 +		{
 +			mAuthURL = message.getValue("url");
 +			mAuthRealm = message.getValue("realm");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
 +		}		
 +		else if(message_name == "debug_message")
 +		{
 +			mDebugMessageText = message.getValue("message_text");
 +			mDebugMessageLevel = message.getValue("message_level");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_DEBUG_MESSAGE);
 +		}
 +		else
 +		{
 +			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
 +		}
 +	}
 +	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
 +	{
 +		std::string message_name = message.getName();
 +		if(message_name == "navigate_begin")
 +		{
 +			mNavigateURI = message.getValue("uri");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN);
 +		}
 +		else if(message_name == "navigate_complete")
 +		{
 +			mNavigateURI = message.getValue("uri");
 +			mNavigateResultCode = message.getValueS32("result_code");
 +			mNavigateResultString = message.getValue("result_string");
 +			mHistoryBackAvailable = message.getValueBoolean("history_back_available");
 +			mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
 +			
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
 +		}
 +		else if(message_name == "progress")
 +		{
 +			mProgressPercent = message.getValueS32("percent");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
 +		}
 +		else if(message_name == "status_text")
 +		{
 +			mStatusText = message.getValue("status");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED);
 +		}
 +		else if(message_name == "location_changed")
 +		{
 +			mLocation = message.getValue("uri");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED);
 +		}
 +		else if(message_name == "click_href")
 +		{
 +			mClickURL = message.getValue("uri");
 +			mClickTarget = message.getValue("target");
 +			mClickUUID = message.getValue("uuid");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
 +		}
 +		else if(message_name == "click_nofollow")
 +		{
 +			mClickURL = message.getValue("uri");
 +			mClickNavType = message.getValue("nav_type");
 +			mClickTarget.clear();
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
 +		}
 +		else if(message_name == "navigate_error_page")
 +		{
 +			mStatusCode = message.getValueS32("status_code");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE);
 +		}
 +		else if(message_name == "cookie_set")
 +		{
 +			if(mOwner)
 +			{
 +				mOwner->handleCookieSet(this, message.getValue("cookie"));
 +			}
 +		}
 +		else if(message_name == "close_request")
 +		{
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST);
 +		}
 +		else if(message_name == "geometry_change")
 +		{
 +			mClickUUID = message.getValue("uuid");
 +			mGeometryX = message.getValueS32("x");
 +			mGeometryY = message.getValueS32("y");
 +			mGeometryWidth = message.getValueS32("width");
 +			mGeometryHeight = message.getValueS32("height");
 +				
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
 +		}
 +		else if(message_name == "link_hovered")
 +		{
 +			// text is not currently used -- the tooltip hover text is taken from the "title".
 +			mHoverLink = message.getValue("link");
 +			mHoverText = message.getValue("title");
 +			// message.getValue("text");
 +				
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
 +		}
 +		else
 +		{
 +			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
 +		}
 +	}
 +	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
 +	{
 +		std::string message_name = message.getName();
 +
 +		// This class hasn't defined any incoming messages yet.
 +//		if(message_name == "message_name")
 +//		{
 +//		}
 +//		else 
 +		{
 +			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
 +		}
 +	}
 +
 +}
 +
 +/* virtual */ 
 +void LLPluginClassMedia::pluginLaunchFailed()
 +{
 +	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
 +}
 +
 +/* virtual */ 
 +void LLPluginClassMedia::pluginDied()
 +{
 +	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
 +}
 +
 +void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event)
 +{
 +	if(mOwner)
 +	{
 +		mOwner->handleMediaEvent(this, event);
 +	}
 +}
 +
 +void LLPluginClassMedia::sendMessage(const LLPluginMessage &message)
 +{
 +	if(mPlugin && mPlugin->isRunning())
 +	{
 +		mPlugin->sendMessage(message);
 +	}
 +	else
 +	{
 +		// The plugin isn't set up yet -- queue this message to be sent after initialization.
 +		mSendQueue.push(message);
 +	}
 +}
 +
 +////////////////////////////////////////////////////////////
 +// MARK: media_browser class functions
 +bool LLPluginClassMedia::pluginSupportsMediaBrowser(void)
 +{
 +	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER);
 +	return !version.empty();
 +}
 +
 +void LLPluginClassMedia::focus(bool focused)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
 +
 +	message.setValueBoolean("focused", focused);
 +	
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::clear_cache()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::clear_cookies()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::set_cookies(const std::string &cookies)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
 +	message.setValue("cookies", cookies);	
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::enable_cookies(bool enable)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
 +	message.setValueBoolean("enable", enable);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup");
 +
 +	message.setValueBoolean("enable", enable);
 +	message.setValue("host", host);
 +	message.setValueS32("port", port);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::browse_stop()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::browse_reload(bool ignore_cache)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
 +
 +	message.setValueBoolean("ignore_cache", ignore_cache);
 +	
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::browse_forward()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::browse_back()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent");
 +
 +	message.setValue("user_agent", user_agent);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::showWebInspector( bool show )
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "show_web_inspector");
 +	message.setValueBoolean("show", true);	// only open for now - closed manually by user
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened");
 +
 +	message.setValue("target", target);
 +	message.setValue("uuid", uuid);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed");
 +
 +	message.setValue("uuid", uuid);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors");
 +	message.setValueBoolean("ignore", ignore);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path");
 +	message.setValue("path", path);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::crashPlugin()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::hangPlugin()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang");
 +
 +	sendMessage(message);
 +}
 +
 +
 +////////////////////////////////////////////////////////////
 +// MARK: media_time class functions
 +bool LLPluginClassMedia::pluginSupportsMediaTime(void)
 +{
 +	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME);
 +	return !version.empty();
 +}
 +
 +void LLPluginClassMedia::stop()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::start(float rate)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start");
 +
 +	message.setValueReal("rate", rate);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::pause()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::seek(float time)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
 +
 +	message.setValueReal("time", time);
 +	
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setLoop(bool loop)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop");
 +
 +	message.setValueBoolean("loop", loop);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setVolume(float volume)
 +{
 +	if(volume != mRequestedVolume)
 +	{
 +		mRequestedVolume = volume;
 +		
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
 +
 +		message.setValueReal("volume", volume);
 +		
 +		sendMessage(message);
 +	}
 +}
 +
 +float LLPluginClassMedia::getVolume()
 +{
 +	return mRequestedVolume;
 +}
 +
 +void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
 +{
 +	// Send URL history to plugin
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history");
 +	message.setValueLLSD("history", url_history);
 +	sendMessage(message);
 +
 +	LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
 +}
 +
 diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index d32cb0afe9..1f548f8cc0 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -118,6 +118,9 @@ public:  	void scrollEvent(int x, int y, MASK modifiers); +	// enable/disable media plugin debugging messages and info spam +	void enableMediaPluginDebugging( bool enable ); +  	// Javascript <-> viewer events  	void jsEnableObject( bool enable );  	void jsAgentLocationEvent( double x, double y, double z ); @@ -209,6 +212,7 @@ public:  	void browse_forward();  	void browse_back();  	void setBrowserUserAgent(const std::string& user_agent); +	void showWebInspector( bool show );  	void proxyWindowOpened(const std::string &target, const std::string &uuid);  	void proxyWindowClosed(const std::string &uuid);  	void ignore_ssl_cert_errors(bool ignore); @@ -244,6 +248,10 @@ public:  	// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE  	std::string getClickUUID() const { return mClickUUID; }; +	// These are valid during MEDIA_EVENT_DEBUG_MESSAGE +	std::string getDebugMessageText() const { return mDebugMessageText; }; +	std::string getDebugMessageLevel() const { return mDebugMessageLevel; }; +  	// This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE  	S32 getStatusCode() const { return mStatusCode; }; @@ -395,6 +403,8 @@ protected:  	std::string		mClickNavType;  	std::string		mClickTarget;  	std::string		mClickUUID; +	std::string		mDebugMessageText; +	std::string		mDebugMessageLevel;  	S32				mGeometryX;  	S32				mGeometryY;  	S32				mGeometryWidth; diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h index 5a4fb1ce90..2f3edba7f3 100644 --- a/indra/llplugin/llpluginclassmediaowner.h +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -64,6 +64,8 @@ public:  		MEDIA_EVENT_AUTH_REQUEST,			// The plugin wants to display an auth dialog +		MEDIA_EVENT_DEBUG_MESSAGE,			// plugin sending back debug information for host to process +  		MEDIA_EVENT_LINK_HOVERED			// Got a "link hovered" event from the plugin  	} EMediaEvent; diff --git a/indra/llplugin/llplugininstance.cpp b/indra/llplugin/llplugininstance.cpp index 7cde82a20e..e8efb233ff 100644 --- a/indra/llplugin/llplugininstance.cpp +++ b/indra/llplugin/llplugininstance.cpp @@ -29,8 +29,7 @@  #include "linden_common.h"  #include "llplugininstance.h" - -#include "llapr.h" +#include "llthread.h"			// Needed for LLThread::tldata().mRootPool  #if LL_WINDOWS  #include "direct.h"	// needed for _chdir() @@ -52,6 +51,7 @@ const char *LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "LLPluginInitEntryPoin   * @param[in] owner Plugin instance. TODO:DOC is this a good description of what "owner" is?   */  LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener *owner) : +	mDSOHandlePool(LLThread::tldata().mRootPool),  	mDSOHandle(NULL),  	mPluginUserData(NULL),  	mPluginSendMessageFunction(NULL) @@ -97,7 +97,7 @@ int LLPluginInstance::load(const std::string& plugin_dir, std::string &plugin_fi  	int result = apr_dso_load(&mDSOHandle,  					  plugin_file.c_str(), -					  gAPRPoolp); +					  mDSOHandlePool());  	if(result != APR_SUCCESS)  	{  		char buf[1024]; diff --git a/indra/llplugin/llplugininstance.h b/indra/llplugin/llplugininstance.h index 3643a15d8c..ee28f68e83 100644 --- a/indra/llplugin/llplugininstance.h +++ b/indra/llplugin/llplugininstance.h @@ -30,6 +30,7 @@  #include "llstring.h"  #include "llapr.h" +#include "llaprpool.h"  #include "apr_dso.h" @@ -88,6 +89,7 @@ private:  	static void staticReceiveMessage(const char *message_string, void **user_data);  	void receiveMessage(const char *message_string); +	LLAPRPool mDSOHandlePool;  	apr_dso_handle_t *mDSOHandle;  	void *mPluginUserData; diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index 8d13e38ad5..dd47300b9c 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -92,8 +92,6 @@ void LLPluginMessagePipeOwner::killMessagePipe(void)  }  LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket): -	mInputMutex(gAPRPoolp), -	mOutputMutex(gAPRPoolp),  	mOwner(owner),  	mSocket(socket)  { diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index f8a282184e..fd63fdde81 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -40,7 +40,7 @@ LLPluginProcessChild::LLPluginProcessChild()  {  	mState = STATE_UNINITIALIZED;  	mInstance = NULL; -	mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); +	mSocket = LLSocket::create(LLSocket::STREAM_TCP);  	mSleepTime = PLUGIN_IDLE_SECONDS;	// default: send idle messages at 100Hz  	mCPUElapsed = 0.0f;  	mBlockingRequest = false; diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 110fac0f23..7aec72731e 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -33,6 +33,7 @@  #include "llpluginmessageclasses.h"  #include "llapr.h" +#include "llscopedvolatileaprpool.h"  //virtual   LLPluginProcessParentOwner::~LLPluginProcessParentOwner() @@ -42,6 +43,7 @@ LLPluginProcessParentOwner::~LLPluginProcessParentOwner()  bool LLPluginProcessParent::sUseReadThread = false;  apr_pollset_t *LLPluginProcessParent::sPollSet = NULL; +LLAPRPool LLPluginProcessParent::sPollSetPool;  bool LLPluginProcessParent::sPollsetNeedsRebuild = false;  LLMutex *LLPluginProcessParent::sInstancesMutex;  std::list<LLPluginProcessParent*> LLPluginProcessParent::sInstances; @@ -52,7 +54,7 @@ class LLPluginProcessParentPollThread: public LLThread  {  public:  	LLPluginProcessParentPollThread() : -		LLThread("LLPluginProcessParentPollThread", gAPRPoolp) +		LLThread("LLPluginProcessParentPollThread")  	{  	}  protected: @@ -77,12 +79,11 @@ protected:  }; -LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner): -	mIncomingQueueMutex(gAPRPoolp) +LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner* owner)  {  	if(!sInstancesMutex)  	{ -		sInstancesMutex = new LLMutex(gAPRPoolp); +		sInstancesMutex = new LLMutex;  	}  	mOwner = owner; @@ -95,6 +96,7 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):  	mBlocked = false;  	mPolledInput = false;  	mPollFD.client_data = NULL; +	mPollFDPool.create();  	mPluginLaunchTimeout = 60.0f;  	mPluginLockupTimeout = 15.0f; @@ -171,44 +173,28 @@ void LLPluginProcessParent::init(const std::string &launcher_filename, const std  bool LLPluginProcessParent::accept()  {  	bool result = false; -	  	apr_status_t status = APR_EGENERAL; -	apr_socket_t *new_socket = NULL; -	 -	status = apr_socket_accept( -		&new_socket, -		mListenSocket->getSocket(), -		gAPRPoolp); +	mSocket = LLSocket::create(status, mListenSocket);  	if(status == APR_SUCCESS)  	{  //		llinfos << "SUCCESS" << llendl;  		// Success.  Create a message pipe on the new socket - -		// we MUST create a new pool for the LLSocket, since it will take ownership of it and delete it in its destructor! -		apr_pool_t* new_pool = NULL; -		status = apr_pool_create(&new_pool, gAPRPoolp); - -		mSocket = LLSocket::create(new_socket, new_pool);  		new LLPluginMessagePipe(this, mSocket);  		result = true;  	} -	else if(APR_STATUS_IS_EAGAIN(status)) -	{ -//		llinfos << "EAGAIN" << llendl; - -		// No incoming connections.  This is not an error. -		status = APR_SUCCESS; -	}  	else  	{ -//		llinfos << "Error:" << llendl; -		ll_apr_warn_status(status); -		 -		// Some other error. -		errorState(); +		mSocket.reset(); +		// EAGAIN means "No incoming connections". This is not an error. +		if (!APR_STATUS_IS_EAGAIN(status)) +		{ +			// Some other error. +			ll_apr_warn_status(status); +			errorState(); +		}  	}  	return result;	 @@ -274,10 +260,10 @@ void LLPluginProcessParent::idle(void)  			case STATE_INITIALIZED:  			{ -	  				apr_status_t status = APR_SUCCESS; +				LLScopedVolatileAPRPool addr_pool;  				apr_sockaddr_t* addr = NULL; -				mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); +				mListenSocket = LLSocket::create(LLSocket::STREAM_TCP);  				mBoundPort = 0;  				// This code is based on parts of LLSocket::create() in lliosocket.cpp. @@ -288,7 +274,7 @@ void LLPluginProcessParent::idle(void)  					APR_INET,  					0,	// port 0 = ephemeral ("find me a port")  					0, -					gAPRPoolp); +					addr_pool);  				if(ll_apr_warn_status(status))  				{ @@ -601,7 +587,7 @@ void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe)  	if(message_pipe != NULL)  	{  		// Set up the apr_pollfd_t -		mPollFD.p = gAPRPoolp; +		mPollFD.p = mPollFDPool();  		mPollFD.desc_type = APR_POLL_SOCKET;  		mPollFD.reqevents = APR_POLLIN|APR_POLLERR|APR_POLLHUP;  		mPollFD.rtnevents = 0; @@ -648,6 +634,7 @@ void LLPluginProcessParent::updatePollset()  		// delete the existing pollset.  		apr_pollset_destroy(sPollSet);  		sPollSet = NULL; +		sPollSetPool.destroy();  	}  	std::list<LLPluginProcessParent*>::iterator iter; @@ -670,12 +657,14 @@ void LLPluginProcessParent::updatePollset()  		{  #ifdef APR_POLLSET_NOCOPY  			// The pollset doesn't exist yet.  Create it now. -			apr_status_t status = apr_pollset_create(&sPollSet, count, gAPRPoolp, APR_POLLSET_NOCOPY); +			sPollSetPool.create(); +			apr_status_t status = apr_pollset_create(&sPollSet, count, sPollSetPool(), APR_POLLSET_NOCOPY);  			if(status != APR_SUCCESS)  			{  #endif // APR_POLLSET_NOCOPY  				LL_WARNS("PluginPoll") << "Couldn't create pollset.  Falling back to non-pollset mode." << LL_ENDL;  				sPollSet = NULL; +				sPollSetPool.destroy();  #ifdef APR_POLLSET_NOCOPY  			}  			else diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index 26c6b0c402..74b7e9f50c 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -178,7 +178,9 @@ private:  	static bool sUseReadThread;  	apr_pollfd_t mPollFD; +	LLAPRPool mPollFDPool;  	static apr_pollset_t *sPollSet; +	static LLAPRPool sPollSetPool;  	static bool sPollsetNeedsRebuild;  	static LLMutex *sInstancesMutex;  	static std::list<LLPluginProcessParent*> sInstances; diff --git a/indra/llplugin/llpluginsharedmemory.cpp b/indra/llplugin/llpluginsharedmemory.cpp index 63ff5085c6..e2ff645a9c 100644 --- a/indra/llplugin/llpluginsharedmemory.cpp +++ b/indra/llplugin/llpluginsharedmemory.cpp @@ -187,7 +187,8 @@ bool LLPluginSharedMemory::create(size_t size)  	mName += createName();  	mSize = size; -	apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), gAPRPoolp ); +	mPool.create(); +	apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), mPool());  	if(ll_apr_warn_status(status))  	{ @@ -210,7 +211,7 @@ bool LLPluginSharedMemory::destroy(void)  		}  		mImpl->mAprSharedMemory = NULL;  	} -	 +	mPool.destroy();  	return true;  } @@ -219,7 +220,8 @@ bool LLPluginSharedMemory::attach(const std::string &name, size_t size)  	mName = name;  	mSize = size; -	apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), gAPRPoolp ); +	mPool.create(); +	apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), mPool() );  	if(ll_apr_warn_status(status))  	{ @@ -241,6 +243,7 @@ bool LLPluginSharedMemory::detach(void)  		}  		mImpl->mAprSharedMemory = NULL;  	} +	mPool.destroy();  	return true;  } diff --git a/indra/llplugin/llpluginsharedmemory.h b/indra/llplugin/llpluginsharedmemory.h index c6cd49cabb..84b7a58c32 100644 --- a/indra/llplugin/llpluginsharedmemory.h +++ b/indra/llplugin/llpluginsharedmemory.h @@ -28,6 +28,8 @@  #ifndef LL_LLPLUGINSHAREDMEMORY_H  #define LL_LLPLUGINSHAREDMEMORY_H +#include "llaprpool.h" +  class LLPluginSharedMemoryPlatformImpl;  /** @@ -108,6 +110,7 @@ private:  	bool close(void);  	bool unlink(void); +	LLAPRPool mPool;  	std::string mName;  	size_t mSize;  	void *mMappedAddress; diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp index 516a58db88..ff86e4e135 100644 --- a/indra/llplugin/slplugin/slplugin.cpp +++ b/indra/llplugin/slplugin/slplugin.cpp @@ -176,8 +176,6 @@ int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdL  int main(int argc, char **argv)  #endif  { -	ll_init_apr(); -  	// Set up llerror logging  	{  		LLError::initForApplication("."); @@ -393,8 +391,6 @@ int main(int argc, char **argv)  	delete plugin; -	ll_cleanup_apr(); -  	return 0;  } diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index d72918b15d..edcc47aa14 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -927,13 +927,7 @@ LLRender::LLRender()      mMode(LLRender::TRIANGLES),      mCurrTextureUnitIndex(0),      mMaxAnisotropy(0.f)  -{ -	mBuffer = new LLVertexBuffer(immediate_mask, 0); -	mBuffer->allocateBuffer(4096, 0, TRUE); -	mBuffer->getVertexStrider(mVerticesp); -	mBuffer->getTexCoord0Strider(mTexcoordsp); -	mBuffer->getColorStrider(mColorsp); -	 +{	  	mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS);  	for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++)  	{ @@ -964,6 +958,17 @@ LLRender::~LLRender()  	shutdown();  } +void LLRender::init() +{ +	llassert_always(mBuffer.isNull()) ; + +	mBuffer = new LLVertexBuffer(immediate_mask, 0); +	mBuffer->allocateBuffer(4096, 0, TRUE); +	mBuffer->getVertexStrider(mVerticesp); +	mBuffer->getTexCoord0Strider(mTexcoordsp); +	mBuffer->getColorStrider(mColorsp); +} +  void LLRender::shutdown()  {  	for (U32 i = 0; i < mTexUnits.size(); i++) @@ -979,6 +984,7 @@ void LLRender::shutdown()  		delete mLightState[i];  	}  	mLightState.clear(); +	mBuffer = NULL ;  }  void LLRender::refreshState(void) diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 9eedebe2ce..8f7ee30d87 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -310,6 +310,7 @@ public:  	LLRender();  	~LLRender(); +	void init() ;  	void shutdown();  	// Refreshes renderer state to the cached values diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index b6a252e8fa..8fd1193780 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -25,7 +25,6 @@   */  #include "linden_common.h" -#include "llmemory.h"  #include <boost/static_assert.hpp>  #include "llsys.h" @@ -36,6 +35,7 @@  #include "llrender.h"  #include "llvector4a.h"  #include "llglslshader.h" +#include "llmemory.h"  //============================================================================ @@ -46,6 +46,7 @@ LLVBOPool LLVertexBuffer::sDynamicVBOPool;  LLVBOPool LLVertexBuffer::sStreamIBOPool;  LLVBOPool LLVertexBuffer::sDynamicIBOPool; +LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL ;  U32 LLVertexBuffer::sBindCount = 0;  U32 LLVertexBuffer::sSetCount = 0;  S32 LLVertexBuffer::sCount = 0; @@ -443,6 +444,11 @@ void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)  	}  	sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ; + +	if(!sPrivatePoolp) +	{ +		sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC) ; +	}  }  //static  @@ -472,7 +478,11 @@ void LLVertexBuffer::cleanupClass()  	unbind();  	clientCopy(); // deletes GL buffers -	//llassert_always(!sCount) ; +	if(sPrivatePoolp) +	{ +		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ; +		sPrivatePoolp = NULL ; +	}  }  void LLVertexBuffer::clientCopy(F64 max_time) @@ -722,7 +732,7 @@ void LLVertexBuffer::createGLBuffer()  	{  		static int gl_buffer_idx = 0;  		mGLBuffer = ++gl_buffer_idx; -		mMappedData = (U8*) ll_aligned_malloc_16(size); +		mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);  	}  } @@ -756,7 +766,7 @@ void LLVertexBuffer::createGLIndices()  	}  	else  	{ -		mMappedIndexData = (U8*) ll_aligned_malloc_16(size); +		mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);  		static int gl_buffer_idx = 0;  		mGLIndices = ++gl_buffer_idx;  	} @@ -779,7 +789,7 @@ void LLVertexBuffer::destroyGLBuffer()  		}  		else  		{ -			ll_aligned_free_16(mMappedData); +			FREE_MEM(sPrivatePoolp, mMappedData) ;  			mMappedData = NULL;  			mEmpty = TRUE;  		} @@ -808,7 +818,7 @@ void LLVertexBuffer::destroyGLIndices()  		}  		else  		{ -			ll_aligned_free_16(mMappedIndexData); +			FREE_MEM(sPrivatePoolp, mMappedIndexData) ;  			mMappedIndexData = NULL;  			mEmpty = TRUE;  		} @@ -941,8 +951,8 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)  			{  				if (!useVBOs())  				{ -					ll_aligned_free_16(mMappedData); -					mMappedData = (U8*) ll_aligned_malloc_16(newsize); +					FREE_MEM(sPrivatePoolp, mMappedData); +					mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, newsize);  				}  				mResized = TRUE;  			} @@ -962,8 +972,8 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)  			{  				if (!useVBOs())  				{ -					ll_aligned_free_16(mMappedIndexData); -					mMappedIndexData = (U8*) ll_aligned_malloc_16(new_index_size); +					FREE_MEM(sPrivatePoolp, mMappedIndexData) ; +					mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, new_index_size);  				}  				mResized = TRUE;  			} @@ -998,8 +1008,8 @@ void LLVertexBuffer::freeClientBuffer()  {  	if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData))  	{ -		ll_aligned_free_16(mMappedData) ; -		ll_aligned_free_16(mMappedIndexData) ; +		FREE_MEM(sPrivatePoolp, mMappedData) ; +		FREE_MEM(sPrivatePoolp, mMappedIndexData) ;  		mMappedData = NULL ;  		mMappedIndexData = NULL ;  	} @@ -1009,7 +1019,7 @@ void LLVertexBuffer::allocateClientVertexBuffer()  {  	if(!mMappedData)  	{ -		mMappedData = (U8*)ll_aligned_malloc_16(getSize()); +		mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, getSize());  	}  } @@ -1017,7 +1027,7 @@ void LLVertexBuffer::allocateClientIndexBuffer()  {  	if(!mMappedIndexData)  	{ -		mMappedIndexData = (U8*)ll_aligned_malloc_16(getIndicesSize()); +		mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, getIndicesSize());		  	}  } @@ -1159,12 +1169,9 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran  			{  				log_glerror(); -				//check the availability of memory -				U32 avail_phy_mem, avail_vir_mem; -				LLMemoryInfo::getAvailableMemoryKB(avail_phy_mem, avail_vir_mem) ; -				llinfos << "Available physical mwmory(KB): " << avail_phy_mem << llendl ;  -				llinfos << "Available virtual memory(KB): " << avail_vir_mem << llendl; - +			//check the availability of memory +			LLMemory::logMemoryInfo(TRUE) ;  +			  				if(!sDisableVBOMapping)  				{			  					//-------------------- @@ -1324,6 +1331,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)  		if (!mMappedIndexData)  		{  			log_glerror(); +			LLMemory::logMemoryInfo(TRUE) ;  			if(!sDisableVBOMapping)  			{ diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index cc5d11e1c2..578cec3885 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -79,7 +79,7 @@ public:  //============================================================================  // base class  - +class LLPrivateMemoryPool ;  class LLVertexBuffer : public LLRefCount  {  public: @@ -282,6 +282,9 @@ protected:  	void waitFence() const; +private: +	static LLPrivateMemoryPool* sPrivatePoolp ; +  public:  	static S32 sCount;  	static S32 sGLCount; diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index cddda03faf..89d8842393 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -525,15 +525,12 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p)  	else  	{  		mButton->setRect(rect); -		mButton->setTabStop(TRUE); -		mButton->setHAlign(LLFontGL::LEFT);  		mButton->setLabel(mLabel.getString());  		if (mTextEntry)  		{  			mTextEntry->setVisible(FALSE);  		} -		mButton->setFollowsAll();  	}  } diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp index 3d3ed9f6d4..bf49b9668e 100644 --- a/indra/llvfs/lllfsthread.cpp +++ b/indra/llvfs/lllfsthread.cpp @@ -67,10 +67,6 @@ LLLFSThread::LLLFSThread(bool threaded) :  	LLQueuedThread("LFS", threaded),  	mPriorityCounter(PRIORITY_LOWBITS)  { -	if(!mLocalAPRFilePoolp) -	{ -		mLocalAPRFilePoolp = new LLVolatileAPRPool() ; -	}  }  LLLFSThread::~LLLFSThread() @@ -182,8 +178,7 @@ bool LLLFSThread::Request::processRequest()  	if (mOperation ==  FILE_READ)  	{  		llassert(mOffset >= 0); -		LLAPRFile infile ; // auto-closes -		infile.open(mFileName, LL_APR_RB, mThread->getLocalAPRFilePool()); +		LLAPRFile infile(mFileName, LL_APR_RB);  		if (!infile.getFileHandle())  		{  			llwarns << "LLLFS: Unable to read file: " << mFileName << llendl; @@ -205,8 +200,7 @@ bool LLLFSThread::Request::processRequest()  		apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;  		if (mOffset < 0)  			flags |= APR_APPEND; -		LLAPRFile outfile ; // auto-closes -		outfile.open(mFileName, flags, mThread->getLocalAPRFilePool()); +		LLAPRFile outfile(mFileName, flags);  		if (!outfile.getFileHandle())  		{  			llwarns << "LLLFS: Unable to write file: " << mFileName << llendl; diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index 82c926620a..ade19f8103 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -234,7 +234,7 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename  	mDataFP(NULL),  	mIndexFP(NULL)  { -	mDataMutex = new LLMutex(0); +	mDataMutex = new LLMutex;  	S32 i;  	for (i = 0; i < VFSLOCK_COUNT; i++) @@ -2098,8 +2098,7 @@ void LLVFS::dumpFiles()  			std::string filename = id.asString() + extension;  			llinfos << " Writing " << filename << llendl; -			LLAPRFile outfile; -			outfile.open(filename, LL_APR_WB); +			LLAPRFile outfile(filename, LL_APR_WB);  			outfile.write(&buffer[0], size);  			outfile.close(); diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index e402061e1f..050d4b729f 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -385,7 +385,8 @@ class LLCachedControl  {  public:  	LLCachedControl(LLControlGroup& group, -					const std::string& name,  +					const std::string& name, +  					const T& default_value,   					const std::string& comment = "Declared In Code")  	{ diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h index 6bc272c009..77d6d19663 100644 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h @@ -37,7 +37,6 @@ extern "C" {  #include <stdio.h>  #include <gst/gst.h> -#include "apr_pools.h"  #include "apr_dso.h"  } diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp index 2e4baaa9eb..93a10424dd 100644 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp @@ -28,16 +28,18 @@  #if LL_GSTREAMER010_ENABLED +#include "linden_common.h" +  #include <string>  extern "C" {  #include <gst/gst.h> -#include "apr_pools.h"  #include "apr_dso.h"  }  #include "llmediaimplgstreamertriviallogging.h" +#include "llaprpool.h"  #define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL  #include "llmediaimplgstreamer_syms_raw.inc" @@ -56,7 +58,7 @@ void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname)  }  static bool sSymsGrabbed = false; -static apr_pool_t *sSymGSTDSOMemoryPool = NULL; +static LLAPRPool sSymGSTDSOMemoryPool;  static apr_dso_handle_t *sSymGSTDSOHandleG = NULL;  static apr_dso_handle_t *sSymGSTDSOHandleV = NULL; @@ -78,11 +80,11 @@ bool grab_gst_syms(std::string gst_dso_name,  #define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0)  	//attempt to load the shared libraries -	apr_pool_create(&sSymGSTDSOMemoryPool, NULL); +	sSymGSTDSOMemoryPool.create();  	if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle,  					       gst_dso_name.c_str(), -					       sSymGSTDSOMemoryPool) )) +					       sSymGSTDSOMemoryPool()) ))  	{  		INFOMSG("Found DSO: %s", gst_dso_name.c_str());  #include "llmediaimplgstreamer_syms_raw.inc" @@ -96,7 +98,7 @@ bool grab_gst_syms(std::string gst_dso_name,  		if ( APR_SUCCESS ==  		     (rv = apr_dso_load(&sSymGSTDSOHandle,  					gst_dso_name_vid.c_str(), -					sSymGSTDSOMemoryPool) )) +					sSymGSTDSOMemoryPool()) ))  		{  			INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str());  #include "llmediaimplgstreamer_syms_rawv.inc" @@ -150,8 +152,7 @@ void ungrab_gst_syms()  	if ( sSymGSTDSOMemoryPool )  	{ -		apr_pool_destroy(sSymGSTDSOMemoryPool); -		sSymGSTDSOMemoryPool = NULL; +		sSymGSTDSOMemoryPool.destroy();  	}  	// NULL-out all of the symbols we'd grabbed diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 91be3a89e9..94dfd80700 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -65,7 +65,7 @@ extern "C" {  #undef LL_PA_SYM  static bool sSymsGrabbed = false; -static apr_pool_t *sSymPADSOMemoryPool = NULL; +static LLAPRPool sSymPADSOMemoryPool;  static apr_dso_handle_t *sSymPADSOHandleG = NULL;  bool grab_pa_syms(std::string pulse_dso_name) @@ -84,11 +84,11 @@ bool grab_pa_syms(std::string pulse_dso_name)  #define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##PASYM, sSymPADSOHandle, #PASYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #PASYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #PASYM, (void*)ll##PASYM);}while(0)  	//attempt to load the shared library -	apr_pool_create(&sSymPADSOMemoryPool, NULL); +	sSymPADSOMemoryPool.create();  	if ( APR_SUCCESS == (rv = apr_dso_load(&sSymPADSOHandle,  					       pulse_dso_name.c_str(), -					       sSymPADSOMemoryPool) )) +					       sSymPADSOMemoryPool()) ))  	{  		INFOMSG("Found DSO: %s", pulse_dso_name.c_str()); @@ -130,12 +130,8 @@ void ungrab_pa_syms()  		apr_dso_unload(sSymPADSOHandleG);  		sSymPADSOHandleG = NULL;  	} -	 -	if ( sSymPADSOMemoryPool ) -	{ -		apr_pool_destroy(sSymPADSOMemoryPool); -		sSymPADSOMemoryPool = NULL; -	} + +	sSymPADSOMemoryPool.destroy();  	// NULL-out all of the symbols we'd grabbed  #define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{ll##PASYM = NULL;}while(0) diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 96f642f2a0..430ae9d4dc 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -1,1394 +1,1447 @@ -/**  - * @file media_plugin_webkit.cpp - * @brief Webkit plugin for LLMedia API plugin system - * - * @cond - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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$ - * @endcond - */ - -#include "llqtwebkit.h" - -#include "linden_common.h" -#include "indra_constants.h" // for indra keyboard codes - -#include "llgl.h" - -#include "llplugininstance.h" -#include "llpluginmessage.h" -#include "llpluginmessageclasses.h" -#include "media_plugin_base.h" - -// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified -#if LL_LINUX -# define LL_QTWEBKIT_USES_PIXMAPS 0 -extern "C" { -# include <glib.h> -# include <glib-object.h> -} -#else -# define LL_QTWEBKIT_USES_PIXMAPS 0 -#endif // LL_LINUX - -# include "volume_catcher.h" - -#if LL_WINDOWS -# include <direct.h> -#else -# include <unistd.h> -# include <stdlib.h> -#endif - -#if LL_WINDOWS -	// *NOTE:Mani - This captures the module handle for the dll. This is used below -	// to get the path to this dll for webkit initialization. -	// I don't know how/if this can be done with apr... -	namespace {	HMODULE gModuleHandle;}; -	BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -	{ -		gModuleHandle = (HMODULE) hinstDLL; -		return TRUE; -	} -#endif - -//////////////////////////////////////////////////////////////////////////////// -// -class MediaPluginWebKit :  -		public MediaPluginBase, -		public LLEmbeddedBrowserWindowObserver -{ -public: -	MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); -	~MediaPluginWebKit(); - -	/*virtual*/ void receiveMessage(const char *message_string); - -private: - -	std::string mProfileDir; -	std::string mHostLanguage; -	std::string mUserAgent; -	bool mCookiesEnabled; -	bool mJavascriptEnabled; -	bool mPluginsEnabled; - -	enum -	{ -		INIT_STATE_UNINITIALIZED,		// LLQtWebkit hasn't been set up yet -		INIT_STATE_INITIALIZED,			// LLQtWebkit has been set up, but no browser window has been created yet. -		INIT_STATE_NAVIGATING,			// Browser instance has been set up and initial navigate to about:blank has been issued -		INIT_STATE_NAVIGATE_COMPLETE,	// initial navigate to about:blank has completed -		INIT_STATE_WAIT_REDRAW,			// First real navigate begin has been received, waiting for page changed event to start handling redraws -		INIT_STATE_WAIT_COMPLETE,		// Waiting for first real navigate complete event -		INIT_STATE_RUNNING				// All initialization gymnastics are complete. -	}; -	int mBrowserWindowId; -	int mInitState; -	std::string mInitialNavigateURL; -	bool mNeedsUpdate; - -	bool	mCanCut; -	bool	mCanCopy; -	bool	mCanPaste; -	int mLastMouseX; -	int mLastMouseY; -	bool mFirstFocus; -	F32 mBackgroundR; -	F32 mBackgroundG; -	F32 mBackgroundB; -	std::string mTarget; -	 -	VolumeCatcher mVolumeCatcher; - -	void setInitState(int state) -	{ -//		std::cerr << "changing init state to " << state << std::endl; -		mInitState = state; -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// -	void update(int milliseconds) -	{ -#if LL_QTLINUX_DOESNT_HAVE_GLIB -		// pump glib generously, as Linux browser plugins are on the -		// glib main loop, even if the browser itself isn't - ugh -		// This is NOT NEEDED if Qt itself was built with glib -		// mainloop integration. -		GMainContext *mainc = g_main_context_default(); -		while(g_main_context_iteration(mainc, FALSE)); -#endif // LL_QTLINUX_DOESNT_HAVE_GLIB - -		// pump qt -		LLQtWebKit::getInstance()->pump( milliseconds ); -		 -		mVolumeCatcher.pump(); - -		checkEditState(); -		 -		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) -		{ -			if(!mInitialNavigateURL.empty()) -			{ -				// We already have the initial navigate URL -- kick off the navigate. -				LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL ); -				mInitialNavigateURL.clear(); -			} -		} -		 -		if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate ) -		{ -			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); - -			unsigned int rowspan = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ); -			unsigned int height = LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId ); -#if !LL_QTWEBKIT_USES_PIXMAPS -			unsigned int buffer_size = rowspan * height; -#endif // !LL_QTWEBKIT_USES_PIXMAPS -			 -//			std::cerr << "webkit plugin: updating" << std::endl; -			 -			// TODO: should get rid of this memcpy if possible -			if ( mPixels && browser_pixels ) -			{ -//				std::cerr << "    memcopy of " << buffer_size << " bytes" << std::endl; - -#if LL_QTWEBKIT_USES_PIXMAPS -				// copy the pixel data upside-down because of the co-ord system -				for (int y=0; y<height; ++y) -				{ -					memcpy( &mPixels[(height-y-1)*rowspan], &browser_pixels[y*rowspan], rowspan ); -				} -#else -				memcpy( mPixels, browser_pixels, buffer_size ); -#endif // LL_QTWEBKIT_USES_PIXMAPS -			} - -			if ( mWidth > 0 && mHeight > 0 ) -			{ -//				std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl; -				setDirty( 0, 0, mWidth, mHeight ); -			} - -			mNeedsUpdate = false; -		}; -	}; - -	//////////////////////////////////////////////////////////////////////////////// -	// -	bool initBrowser() -	{ -		// already initialized -		if ( mInitState > INIT_STATE_UNINITIALIZED ) -			return true; - -		// set up directories -		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use -		if (NULL == getcwd( cwd, FILENAME_MAX - 1 )) -		{ -			llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl; -			return false; -		} -		std::string application_dir = std::string( cwd ); - -#if LL_LINUX -		// take care to initialize glib properly, because some -		// versions of Qt don't, and we indirectly need it for (some -		// versions of) Flash to not crash the browser. -		if (!g_thread_supported ()) g_thread_init (NULL); -		g_type_init(); -#endif - -#if LL_DARWIN -		// When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on. -		// This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger. -		// This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it -		// which gets hit when the plugin is probed by webkit. -		// Unsetting the environment variable here works around this issue. -		unsetenv("USERBREAK"); -#endif - -#if LL_WINDOWS -		//*NOTE:Mani - On windows, at least, the component path is the -		// location of this dll's image file.  -		std::string component_dir; -		char dll_path[_MAX_PATH]; -		DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH); -		while(len && dll_path[ len ] != ('\\') ) -		{ -			len--; -		} -		if(len >= 0) -		{ -			dll_path[len] = 0; -			component_dir = dll_path; -		} -		else -		{ -			// *NOTE:Mani - This case should be an rare exception.  -			// GetModuleFileNameA should always give you a full path, no? -			component_dir = application_dir; -		} -#else -		std::string component_dir = application_dir; -#endif - -		// window handle - needed on Windows and must be app window. -#if LL_WINDOWS -		char window_title[ MAX_PATH ]; -		GetConsoleTitleA( window_title, MAX_PATH ); -		void* native_window_handle = (void*)FindWindowA( NULL, window_title ); -#else -		void* native_window_handle = 0; -#endif - -		// main browser initialization -		bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle ); -		if ( result ) -		{ -			mInitState = INIT_STATE_INITIALIZED; -			 -			return true; -		}; - -		return false; -	}; - -	//////////////////////////////////////////////////////////////////////////////// -	// -	bool initBrowserWindow() -	{ -		// already initialized -		if ( mInitState > INIT_STATE_INITIALIZED ) -			return true; - -		// not enough information to initialize the browser yet. -		if ( mWidth < 0 || mHeight < 0 || mDepth < 0 ||  -				mTextureWidth < 0 || mTextureHeight < 0 ) -		{ -			return false; -		}; -		 -		// Set up host language before creating browser window -		if(!mHostLanguage.empty()) -		{ -			LLQtWebKit::getInstance()->setHostLanguage(mHostLanguage); -		} - -		// turn on/off cookies based on what host app tells us -		LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled ); - -		// turn on/off plugins based on what host app tells us -		LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled ); - -		// turn on/off Javascript based on what host app tells us -		LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled ); -		 -		// create single browser window -		mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget); - -		// tell LLQtWebKit about the size of the browser window -		LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); - -		// observer events that LLQtWebKit emits -		LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); - -		// append details to agent string -		LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent ); -		 -#if !LL_QTWEBKIT_USES_PIXMAPS -		// don't flip bitmap -		LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); -#endif // !LL_QTWEBKIT_USES_PIXMAPS - -		// set background color -		// convert background color channels from [0.0, 1.0] to [0, 255]; -		LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) ); - -		// Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns. -		setInitState(INIT_STATE_NAVIGATING); - -		// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. -		// FIXME: Re-added this because navigating to a "page" initializes things correctly - especially -		// for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date. -		// Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E" -		// where RRGGBB is the background color in HTML style -		std::stringstream url; -		 -		url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#"; -		// convert background color channels from [0.0, 1.0] to [0, 255]; -		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f); -		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f); -		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f); -		url << "%22%3E%3C/body%3E%3C/html%3E"; -		 -		//lldebugs << "data url is: " << url.str() << llendl; -					 -		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() ); -//		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" ); - -		return true;	 -	} - -	void setVolume(F32 vol); - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onCursorChanged(const EventType& event) -	{ -		LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue(); -		std::string name; - -		switch(llqt_cursor) -		{ -			case LLQtWebKit::C_ARROW: -				name = "arrow"; -			break; -			case LLQtWebKit::C_IBEAM: -				name = "ibeam"; -			break; -			case LLQtWebKit::C_SPLITV: -				name = "splitv"; -			break; -			case LLQtWebKit::C_SPLITH: -				name = "splith"; -			break; -			case LLQtWebKit::C_POINTINGHAND: -				name = "hand"; -			break; -			 -			default: -				llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl; -			break; -		} -		 -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed"); -		message.setValue("name", name); -		sendMessage(message); -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onPageChanged( const EventType& event ) -	{ -		if(mInitState == INIT_STATE_WAIT_REDRAW) -		{ -			setInitState(INIT_STATE_WAIT_COMPLETE); -		} -		 -		// flag that an update is required -		mNeedsUpdate = true; -	}; - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onNavigateBegin(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); -			message.setValue("uri", event.getEventUri()); -			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); -			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); -			sendMessage(message); -		 -			setStatus(STATUS_LOADING); -		} - -		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) -		{ -			// Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary. -//			setInitState(INIT_STATE_WAIT_REDRAW); -			setInitState(INIT_STATE_WAIT_COMPLETE); -		} -		 -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onNavigateComplete(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			if(mInitState < INIT_STATE_RUNNING) -			{ -				setInitState(INIT_STATE_RUNNING); -				 -				// Clear the history, so the "back" button doesn't take you back to "about:blank". -				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); -			} -			 -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); -			message.setValue("uri", event.getEventUri()); -			message.setValueS32("result_code", event.getIntValue()); -			message.setValue("result_string", event.getStringValue()); -			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); -			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); -			sendMessage(message); -			 -			setStatus(STATUS_LOADED); -		} -		else if(mInitState == INIT_STATE_NAVIGATING) -		{ -			setInitState(INIT_STATE_NAVIGATE_COMPLETE); -		} - -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onUpdateProgress(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress"); -			message.setValueS32("percent", event.getIntValue()); -			sendMessage(message); -		} -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onStatusTextChange(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text"); -			message.setValue("status", event.getStringValue()); -			sendMessage(message); -		} -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onTitleChange(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); -			message.setValue("name", event.getStringValue()); -			sendMessage(message); -		} -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onNavigateErrorPage(const EventType& event) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page"); -		message.setValueS32("status_code", event.getIntValue()); -		sendMessage(message); -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onLocationChange(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed"); -			message.setValue("uri", event.getEventUri()); -			sendMessage(message); -		} -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onClickLinkHref(const EventType& event) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); -		message.setValue("uri", event.getEventUri()); -		message.setValue("target", event.getStringValue()); -		message.setValue("uuid", event.getStringValue2()); -		sendMessage(message); -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onClickLinkNoFollow(const EventType& event) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); -		message.setValue("uri", event.getEventUri()); -#if LLQTWEBKIT_API_VERSION >= 7 -		message.setValue("nav_type", event.getNavigationType()); -#else -		message.setValue("nav_type", "clicked"); -#endif -		sendMessage(message); -	} -	 - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onCookieChanged(const EventType& event) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookie_set"); -		message.setValue("cookie", event.getStringValue()); -		// These could be passed through as well, but aren't really needed. -//		message.setValue("uri", event.getEventUri()); -//		message.setValueBoolean("dead", (event.getIntValue() != 0)) -		sendMessage(message); -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onWindowCloseRequested(const EventType& event) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request"); -		message.setValue("uuid", event.getStringValue()); -		sendMessage(message); -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onWindowGeometryChangeRequested(const EventType& event) -	{ -		int x, y, width, height; -		event.getRectValue(x, y, width, height); - -		// This sometimes gets called with a zero-size request.  Don't pass these along. -		if(width > 0 && height > 0) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change"); -			message.setValue("uuid", event.getStringValue()); -			message.setValueS32("x", x); -			message.setValueS32("y", y); -			message.setValueS32("width", width); -			message.setValueS32("height", height); -			sendMessage(message); -		} -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	std::string onRequestFilePicker( const EventType& eventIn ) -	{ -		return blockingPickFile(); -	} -	 -	std::string mAuthUsername; -	std::string mAuthPassword; -	bool mAuthOK; -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) -	{ -		mAuthOK = false; - -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request"); -		message.setValue("url", in_url); -		message.setValue("realm", in_realm); -		message.setValueBoolean("blocking_request", true); -				 -		// The "blocking_request" key in the message means this sendMessage call will block until a response is received. -		sendMessage(message); -		 -		if(mAuthOK) -		{ -			out_username = mAuthUsername; -			out_password = mAuthPassword; -		} -		 -		return mAuthOK; -	} -	 -	void authResponse(LLPluginMessage &message) -	{ -		mAuthOK = message.getValueBoolean("ok"); -		if(mAuthOK) -		{ -			mAuthUsername = message.getValue("username"); -			mAuthPassword = message.getValue("password"); -		} -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onLinkHovered(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered"); -			message.setValue("link", event.getEventUri()); -			message.setValue("title", event.getStringValue()); -			message.setValue("text", event.getStringValue2()); -			sendMessage(message); -		} -	} -	 -	LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers) -	{ -		int result = 0; -		 -		if(modifiers.find("shift") != std::string::npos) -			result |= LLQtWebKit::KM_MODIFIER_SHIFT; - -		if(modifiers.find("alt") != std::string::npos) -			result |= LLQtWebKit::KM_MODIFIER_ALT; -		 -		if(modifiers.find("control") != std::string::npos) -			result |= LLQtWebKit::KM_MODIFIER_CONTROL; -		 -		if(modifiers.find("meta") != std::string::npos) -			result |= LLQtWebKit::KM_MODIFIER_META; -		 -		return (LLQtWebKit::EKeyboardModifier)result; -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// -	void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers ) -	{ -		native_scan_code = 0; -		native_virtual_key = 0; -		native_modifiers = 0; -		 -		if( native_key_data.isMap() ) -		{ -#if LL_DARWIN -			native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger()); -			native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger()); -			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); -#elif LL_WINDOWS -			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); -			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); -			// TODO: I don't think we need to do anything with native modifiers here -- please verify -#elif LL_LINUX -			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); -			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); -			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); -#else -			// Add other platforms here as needed -#endif -		}; -	}; - -	//////////////////////////////////////////////////////////////////////////////// -	// -	void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) -	{ -		// The incoming values for 'key' will be the ones from indra_constants.h -		std::string utf8_text; -		 -		if(key < KEY_SPECIAL) -		{ -			// Low-ascii characters need to get passed through. -			utf8_text = (char)key; -		} -		 -		// Any special-case handling we want to do for particular keys... -		switch((KEY)key) -		{ -			// ASCII codes for some standard keys -			case LLQtWebKit::KEY_BACKSPACE:		utf8_text = (char)8;		break; -			case LLQtWebKit::KEY_TAB:			utf8_text = (char)9;		break; -			case LLQtWebKit::KEY_RETURN:		utf8_text = (char)13;		break; -			case LLQtWebKit::KEY_PAD_RETURN:	utf8_text = (char)13;		break; -			case LLQtWebKit::KEY_ESCAPE:		utf8_text = (char)27;		break; -			 -			default:   -			break; -		} -		 -//		std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl; -		 -		uint32_t native_scan_code = 0; -		uint32_t native_virtual_key = 0; -		uint32_t native_modifiers = 0; -		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); -		 -		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); - -		checkEditState(); -	}; - -	//////////////////////////////////////////////////////////////////////////////// -	// -	void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) -	{		 -		uint32_t key = LLQtWebKit::KEY_NONE; -		 -//		std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl; -		 -		if(utf8str.size() == 1) -		{ -			// The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character. -			// In this case, use it as the key value. -			key = utf8str[0]; -		} - -		uint32_t native_scan_code = 0; -		uint32_t native_virtual_key = 0; -		uint32_t native_modifiers = 0; -		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); -		 -		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); -		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); - -		checkEditState(); -	}; -	 -	void checkEditState(void) -	{ -		bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT); -		bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY); -		bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE); -					 -		if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); -			 -			if(can_cut != mCanCut) -			{ -				mCanCut = can_cut; -				message.setValueBoolean("cut", can_cut); -			} - -			if(can_copy != mCanCopy) -			{ -				mCanCopy = can_copy; -				message.setValueBoolean("copy", can_copy); -			} - -			if(can_paste != mCanPaste) -			{ -				mCanPaste = can_paste; -				message.setValueBoolean("paste", can_paste); -			} -			 -			sendMessage(message); -			 -		} -	} -	 -	std::string mPickedFile; -	 -	std::string blockingPickFile(void) -	{ -		mPickedFile.clear(); -		 -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file"); -		message.setValueBoolean("blocking_request", true); -		 -		// The "blocking_request" key in the message means this sendMessage call will block until a response is received. -		sendMessage(message); -		 -		return mPickedFile; -	} - -	void onPickFileResponse(const std::string &file) -	{ -		mPickedFile = file; -	} - -}; - -MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : -	MediaPluginBase(host_send_func, host_user_data) -{ -//	std::cerr << "MediaPluginWebKit constructor" << std::endl; - -	mBrowserWindowId = 0; -	mInitState = INIT_STATE_UNINITIALIZED; -	mNeedsUpdate = true; -	mCanCut = false; -	mCanCopy = false; -	mCanPaste = false; -	mLastMouseX = 0; -	mLastMouseY = 0; -	mFirstFocus = true; -	mBackgroundR = 0.0f; -	mBackgroundG = 0.0f; -	mBackgroundB = 0.0f; - -	mHostLanguage = "en";		// default to english -	mJavascriptEnabled = true;	// default to on -	mPluginsEnabled = true;		// default to on -	mUserAgent = "LLPluginMedia Web Browser"; -} - -MediaPluginWebKit::~MediaPluginWebKit() -{ -	// unhook observer -	LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); - -	// clean up -	LLQtWebKit::getInstance()->reset(); - -//	std::cerr << "MediaPluginWebKit destructor" << std::endl; -} - -void MediaPluginWebKit::receiveMessage(const char *message_string) -{ -//	std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; -	LLPluginMessage message_in; -	 -	if(message_in.parse(message_string) >= 0) -	{ -		std::string message_class = message_in.getClass(); -		std::string message_name = message_in.getName(); -		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) -		{ -			if(message_name == "init") -			{ -				LLPluginMessage message("base", "init_response"); -				LLSD versions = LLSD::emptyMap(); -				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; -				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; -				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; -				message.setValueLLSD("versions", versions); - -				std::string plugin_version = "Webkit media plugin, Webkit version "; -				plugin_version += LLQtWebKit::getInstance()->getVersion(); -				message.setValue("plugin_version", plugin_version); -				sendMessage(message); -			} -			else if(message_name == "idle") -			{ -				// no response is necessary here. -				F64 time = message_in.getValueReal("time"); -				 -				// Convert time to milliseconds for update() -				update((int)(time * 1000.0f)); -			} -			else if(message_name == "cleanup") -			{ -				// DTOR most likely won't be called but the recent change to the way this process -				// is (not) killed means we see this message and can do what we need to here. -				// Note: this cleanup is ultimately what writes cookies to the disk -				LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); -				LLQtWebKit::getInstance()->reset(); -			} -			else if(message_name == "shm_added") -			{ -				SharedSegmentInfo info; -				info.mAddress = message_in.getValuePointer("address"); -				info.mSize = (size_t)message_in.getValueS32("size"); -				std::string name = message_in.getValue("name"); -				 -//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name  -//					<< ", size: " << info.mSize  -//					<< ", address: " << info.mAddress  -//					<< std::endl; - -				mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); -			 -			} -			else if(message_name == "shm_remove") -			{ -				std::string name = message_in.getValue("name"); -				 -//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl; - -				SharedSegmentMap::iterator iter = mSharedSegments.find(name); -				if(iter != mSharedSegments.end()) -				{ -					if(mPixels == iter->second.mAddress) -					{ -						// This is the currently active pixel buffer.  Make sure we stop drawing to it. -						mPixels = NULL; -						mTextureSegmentName.clear(); -					} -					mSharedSegments.erase(iter); -				} -				else -				{ -//					std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; -				} - -				// Send the response so it can be cleaned up. -				LLPluginMessage message("base", "shm_remove_response"); -				message.setValue("name", name); -				sendMessage(message); -			} -			else -			{ -//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; -			} -		} -		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) -		{ -			if(message_name == "set_volume") -			{ -				F32 volume = message_in.getValueReal("volume"); -				setVolume(volume); -			} -		} -		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) -		{ -			if(message_name == "init") -			{ -				mTarget = message_in.getValue("target"); -				 -				// This is the media init message -- all necessary data for initialization should have been received. -				if(initBrowser()) -				{ -					 -					// Plugin gets to decide the texture parameters to use. -					mDepth = 4; - -					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); -					message.setValueS32("default_width", 1024); -					message.setValueS32("default_height", 1024); -					message.setValueS32("depth", mDepth); -					message.setValueU32("internalformat", GL_RGBA); -	#if LL_QTWEBKIT_USES_PIXMAPS -					message.setValueU32("format", GL_BGRA_EXT); // I hope this isn't system-dependant... is it?  If so, we'll have to check the root window's pixel layout or something... yuck. -	#else -					message.setValueU32("format", GL_RGBA); -	#endif // LL_QTWEBKIT_USES_PIXMAPS -					message.setValueU32("type", GL_UNSIGNED_BYTE); -					message.setValueBoolean("coords_opengl", true); -					sendMessage(message); -				} -				else -				{ -					// if initialization failed, we're done. -					mDeleteMe = true; -				} - -			} -			else if(message_name == "set_user_data_path") -			{ -				std::string user_data_path = message_in.getValue("path"); // n.b. always has trailing platform-specific dir-delimiter -				mProfileDir = user_data_path + "browser_profile"; - -				// FIXME: Should we do anything with this if it comes in after the browser has been initialized? -			} -			else if(message_name == "set_language_code") -			{ -				mHostLanguage = message_in.getValue("language"); - -				// FIXME: Should we do anything with this if it comes in after the browser has been initialized? -			} -			else if(message_name == "plugins_enabled") -			{ -				mPluginsEnabled = message_in.getValueBoolean("enable"); -			} -			else if(message_name == "javascript_enabled") -			{ -				mJavascriptEnabled = message_in.getValueBoolean("enable"); -			} -			else if(message_name == "size_change") -			{ -				std::string name = message_in.getValue("name"); -				S32 width = message_in.getValueS32("width"); -				S32 height = message_in.getValueS32("height"); -				S32 texture_width = message_in.getValueS32("texture_width"); -				S32 texture_height = message_in.getValueS32("texture_height"); -				mBackgroundR = message_in.getValueReal("background_r"); -				mBackgroundG = message_in.getValueReal("background_g"); -				mBackgroundB = message_in.getValueReal("background_b"); -//				mBackgroundA = message_in.setValueReal("background_a");		// Ignore any alpha -								 -				if(!name.empty()) -				{ -					// Find the shared memory region with this name -					SharedSegmentMap::iterator iter = mSharedSegments.find(name); -					if(iter != mSharedSegments.end()) -					{ -						mPixels = (unsigned char*)iter->second.mAddress; -						mWidth = width; -						mHeight = height; - -						if(initBrowserWindow()) -						{ - -							// size changed so tell the browser -							LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); -							 -	//						std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight  -	//								<< ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl; -									 -							S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId);  -							 -							// The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response. -							if(real_width <= texture_width) -							{ -								texture_width = real_width; -							} -							else -							{ -								// This won't work -- it'll be bigger than the allocated memory.  This is a fatal error. -	//							std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl; -								mDeleteMe = true; -								return; -							} -						} -						else -						{ -							// Setting up the browser window failed.  This is a fatal error. -							mDeleteMe = true; -						} - -						 -						mTextureWidth = texture_width; -						mTextureHeight = texture_height; -						 -					}; -				}; - -				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); -				message.setValue("name", name); -				message.setValueS32("width", width); -				message.setValueS32("height", height); -				message.setValueS32("texture_width", texture_width); -				message.setValueS32("texture_height", texture_height); -				sendMessage(message); - -			} -			else if(message_name == "load_uri") -			{ -				std::string uri = message_in.getValue("uri"); - -//				std::cout << "loading URI: " << uri << std::endl; -				 -				if(!uri.empty()) -				{ -					if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -					{ -						LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri ); -					} -					else -					{ -						mInitialNavigateURL = uri; -					} -				} -			} -			else if(message_name == "mouse_event") -			{ -				std::string event = message_in.getValue("event"); -				S32 button = message_in.getValueS32("button"); -				mLastMouseX = message_in.getValueS32("x"); -				mLastMouseY = message_in.getValueS32("y"); -				std::string modifiers = message_in.getValue("modifiers"); -				 -				// Treat unknown mouse events as mouse-moves. -				LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE; -				if(event == "down") -				{ -					mouse_event = LLQtWebKit::ME_MOUSE_DOWN; -				} -				else if(event == "up") -				{ -					mouse_event = LLQtWebKit::ME_MOUSE_UP; -				} -				else if(event == "double_click") -				{ -					mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK; -				} -				 -				LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers)); -				checkEditState(); -			} -			else if(message_name == "scroll_event") -			{ -				S32 x = message_in.getValueS32("x"); -				S32 y = message_in.getValueS32("y"); -				std::string modifiers = message_in.getValue("modifiers"); -				 -				// Incoming scroll events are adjusted so that 1 detent is approximately 1 unit. -				// Qt expects 1 detent to be 120 units. -				// It also seems that our y scroll direction is inverted vs. what Qt expects. -				 -				x *= 120; -				y *= -120; -				 -				LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers)); -			} -			else if(message_name == "key_event") -			{ -				std::string event = message_in.getValue("event"); -				S32 key = message_in.getValueS32("key"); -				std::string modifiers = message_in.getValue("modifiers"); -				LLSD native_key_data = message_in.getValueLLSD("native_key_data"); -				 -				// Treat unknown events as key-up for safety. -				LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP; -				if(event == "down") -				{ -					key_event = LLQtWebKit::KE_KEY_DOWN; -				} -				else if(event == "repeat") -				{ -					key_event = LLQtWebKit::KE_KEY_REPEAT; -				} -				 -				keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data); -			} -			else if(message_name == "text_event") -			{ -				std::string text = message_in.getValue("text"); -				std::string modifiers = message_in.getValue("modifiers"); -				LLSD native_key_data = message_in.getValueLLSD("native_key_data"); -				 -				unicodeInput(text, decodeModifiers(modifiers), native_key_data); -			} -			if(message_name == "edit_cut") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT ); -				checkEditState(); -			} -			if(message_name == "edit_copy") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY ); -				checkEditState(); -			} -			if(message_name == "edit_paste") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE ); -				checkEditState(); -			} -			if(message_name == "pick_file_response") -			{ -				onPickFileResponse(message_in.getValue("file")); -			} -			if(message_name == "auth_response") -			{ -				authResponse(message_in); -			} -			else -			if(message_name == "js_enable_object") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				bool enable = message_in.getValueBoolean( "enable" ); -				LLQtWebKit::getInstance()->setSLObjectEnabled( enable ); -#endif -			} -			else -			if(message_name == "js_agent_location") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				F32 x = message_in.getValueReal("x"); -				F32 y = message_in.getValueReal("y"); -				F32 z = message_in.getValueReal("z"); -				LLQtWebKit::getInstance()->setAgentLocation( x, y, z ); -				LLQtWebKit::getInstance()->emitLocation(); -#endif -			} -			else -			if(message_name == "js_agent_global_location") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				F32 x = message_in.getValueReal("x"); -				F32 y = message_in.getValueReal("y"); -				F32 z = message_in.getValueReal("z"); -				LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z ); -				LLQtWebKit::getInstance()->emitLocation(); -#endif -			} -			else			 -			if(message_name == "js_agent_orientation") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				F32 angle = message_in.getValueReal("angle"); -				LLQtWebKit::getInstance()->setAgentOrientation( angle ); -				LLQtWebKit::getInstance()->emitLocation(); -#endif -			} -			else -			if(message_name == "js_agent_region") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				const std::string& region = message_in.getValue("region"); -				LLQtWebKit::getInstance()->setAgentRegion( region ); -				LLQtWebKit::getInstance()->emitLocation(); -#endif -			} -			else -				if(message_name == "js_agent_maturity") -				{ -#if LLQTWEBKIT_API_VERSION >= 9 -					const std::string& maturity = message_in.getValue("maturity"); -					LLQtWebKit::getInstance()->setAgentMaturity( maturity ); -					LLQtWebKit::getInstance()->emitMaturity(); -#endif -				} -			else -			if(message_name == "js_agent_language") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				const std::string& language = message_in.getValue("language"); -				LLQtWebKit::getInstance()->setAgentLanguage( language ); -				LLQtWebKit::getInstance()->emitLanguage(); -#endif -			} -			else -			{ -//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; -			} -		} -		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) -		{ -			if(message_name == "focus") -			{ -				bool val = message_in.getValueBoolean("focused"); -				LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val ); -				 -				if(mFirstFocus && val) -				{ -					// On the first focus, post a tab key event.  This fixes a problem with initial focus. -					std::string empty; -					keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty)); -					keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty)); -					mFirstFocus = false; -				} -			} -			else if(message_name == "clear_cache") -			{ -				LLQtWebKit::getInstance()->clearCache(); -			} -			else if(message_name == "clear_cookies") -			{ -				LLQtWebKit::getInstance()->clearAllCookies(); -			} -			else if(message_name == "enable_cookies") -			{ -				mCookiesEnabled = message_in.getValueBoolean("enable"); -				LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled ); -			} -			else if(message_name == "enable_plugins") -			{ -				mPluginsEnabled = message_in.getValueBoolean("enable"); -				LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled ); -			} -			else if(message_name == "enable_javascript") -			{ -				mJavascriptEnabled = message_in.getValueBoolean("enable"); -				//LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled ); -			} -			else if(message_name == "set_cookies") -			{ -				LLQtWebKit::getInstance()->setCookies(message_in.getValue("cookies")); -			} -			else if(message_name == "proxy_setup") -			{ -				bool val = message_in.getValueBoolean("enable"); -				std::string host = message_in.getValue("host"); -				int port = message_in.getValueS32("port"); -				LLQtWebKit::getInstance()->enableProxy( val, host, port ); -			} -			else if(message_name == "browse_stop") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP ); -			} -			else if(message_name == "browse_reload") -			{ -				// foo = message_in.getValueBoolean("ignore_cache"); -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD ); -			} -			else if(message_name == "browse_forward") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD ); -			} -			else if(message_name == "browse_back") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK ); -			} -			else if(message_name == "set_status_redirect") -			{ -				int code = message_in.getValueS32("code"); -				std::string url = message_in.getValue("url"); -				if ( 404 == code )	// browser lib only supports 404 right now -				{ -#if LLQTWEBKIT_API_VERSION < 8 -				 	LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url ); -#endif -				}; -			} -			else if(message_name == "set_user_agent") -			{ -				mUserAgent = message_in.getValue("user_agent"); -				LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent ); -			} -			else if(message_name == "ignore_ssl_cert_errors") -			{ -#if LLQTWEBKIT_API_VERSION >= 3 -				LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") ); -#else -				llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl; -#endif -			} -			else if(message_name == "add_certificate_file_path") -			{ -#if LLQTWEBKIT_API_VERSION >= 6 -				LLQtWebKit::getInstance()->setCAFile( message_in.getValue("path") ); -#else -				llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl; -#endif -			} -			else if(message_name == "init_history") -			{ -				// Initialize browser history -				LLSD history = message_in.getValueLLSD("history"); -				// First, clear the URL history -				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); -				// Then, add the history items in order -				LLSD::array_iterator iter_history = history.beginArray(); -				LLSD::array_iterator end_history = history.endArray(); -				for(; iter_history != end_history; ++iter_history) -				{ -					std::string url = (*iter_history).asString(); -					if(! url.empty()) { -						LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url); -					} -				} -			} -			else if(message_name == "proxy_window_opened") -			{ -				std::string target = message_in.getValue("target"); -				std::string uuid = message_in.getValue("uuid"); -				LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid); -			} -			else if(message_name == "proxy_window_closed") -			{ -				std::string uuid = message_in.getValue("uuid"); -				LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid); -			} -			else -			{ -//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl; -			}; -		} -		else -		{ -//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; -		}; -	} -} - -void MediaPluginWebKit::setVolume(F32 volume) -{ -	mVolumeCatcher.setVolume(volume); -} - -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -{ -	MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data); -	*plugin_send_func = MediaPluginWebKit::staticReceiveMessage; -	*plugin_user_data = (void*)self; - -	return 0; -} - - +/** 
 + * @file media_plugin_webkit.cpp
 + * @brief Webkit plugin for LLMedia API plugin system
 + *
 + * @cond
 + * $LicenseInfo:firstyear=2008&license=viewerlgpl$
 + * Second Life Viewer Source Code
 + * Copyright (C) 2010, 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$
 + * @endcond
 + */
 +
 +#include "llqtwebkit.h"
 +
 +#include "linden_common.h"
 +#include "indra_constants.h" // for indra keyboard codes
 +
 +#include "llgl.h"
 +
 +#include "llplugininstance.h"
 +#include "llpluginmessage.h"
 +#include "llpluginmessageclasses.h"
 +#include "media_plugin_base.h"
 +
 +// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified
 +#if LL_LINUX
 +# define LL_QTWEBKIT_USES_PIXMAPS 0
 +extern "C" {
 +# include <glib.h>
 +# include <glib-object.h>
 +}
 +#else
 +# define LL_QTWEBKIT_USES_PIXMAPS 0
 +#endif // LL_LINUX
 +
 +# include "volume_catcher.h"
 +
 +#if LL_WINDOWS
 +# include <direct.h>
 +#else
 +# include <unistd.h>
 +# include <stdlib.h>
 +#endif
 +
 +#if LL_WINDOWS
 +	// *NOTE:Mani - This captures the module handle for the dll. This is used below
 +	// to get the path to this dll for webkit initialization.
 +	// I don't know how/if this can be done with apr...
 +	namespace {	HMODULE gModuleHandle;};
 +	BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 +	{
 +		gModuleHandle = (HMODULE) hinstDLL;
 +		return TRUE;
 +	}
 +#endif
 +
 +////////////////////////////////////////////////////////////////////////////////
 +//
 +class MediaPluginWebKit : 
 +		public MediaPluginBase,
 +		public LLEmbeddedBrowserWindowObserver
 +{
 +public:
 +	MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
 +	~MediaPluginWebKit();
 +
 +	/*virtual*/ void receiveMessage(const char *message_string);
 +
 +private:
 +
 +	std::string mProfileDir;
 +	std::string mHostLanguage;
 +	std::string mUserAgent;
 +	bool mCookiesEnabled;
 +	bool mJavascriptEnabled;
 +	bool mPluginsEnabled;
 +	bool mEnableMediaPluginDebugging;
 +
 +	enum
 +	{
 +		INIT_STATE_UNINITIALIZED,		// LLQtWebkit hasn't been set up yet
 +		INIT_STATE_INITIALIZED,			// LLQtWebkit has been set up, but no browser window has been created yet.
 +		INIT_STATE_NAVIGATING,			// Browser instance has been set up and initial navigate to about:blank has been issued
 +		INIT_STATE_NAVIGATE_COMPLETE,	// initial navigate to about:blank has completed
 +		INIT_STATE_WAIT_REDRAW,			// First real navigate begin has been received, waiting for page changed event to start handling redraws
 +		INIT_STATE_WAIT_COMPLETE,		// Waiting for first real navigate complete event
 +		INIT_STATE_RUNNING				// All initialization gymnastics are complete.
 +	};
 +	int mBrowserWindowId;
 +	int mInitState;
 +	std::string mInitialNavigateURL;
 +	bool mNeedsUpdate;
 +
 +	bool	mCanCut;
 +	bool	mCanCopy;
 +	bool	mCanPaste;
 +	int mLastMouseX;
 +	int mLastMouseY;
 +	bool mFirstFocus;
 +	F32 mBackgroundR;
 +	F32 mBackgroundG;
 +	F32 mBackgroundB;
 +	std::string mTarget;
 +	
 +	VolumeCatcher mVolumeCatcher;
 +
 +	void postDebugMessage( const std::string& msg )
 +	{
 +		if ( mEnableMediaPluginDebugging )
 +		{
 +			LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message");
 +			debug_message.setValue("message_text", "Media> " + msg);
 +			debug_message.setValue("message_level", "info");
 +			sendMessage(debug_message);
 +		}
 +	}
 +	
 +	void setInitState(int state)
 +	{
 +//		std::cerr << "changing init state to " << state << std::endl;
 +		mInitState = state;
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	void update(int milliseconds)
 +	{
 +#if LL_QTLINUX_DOESNT_HAVE_GLIB
 +		// pump glib generously, as Linux browser plugins are on the
 +		// glib main loop, even if the browser itself isn't - ugh
 +		// This is NOT NEEDED if Qt itself was built with glib
 +		// mainloop integration.
 +		GMainContext *mainc = g_main_context_default();
 +		while(g_main_context_iteration(mainc, FALSE));
 +#endif // LL_QTLINUX_DOESNT_HAVE_GLIB
 +
 +		// pump qt
 +		LLQtWebKit::getInstance()->pump( milliseconds );
 +		
 +		mVolumeCatcher.pump();
 +
 +		checkEditState();
 +		
 +		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			if(!mInitialNavigateURL.empty())
 +			{
 +				// We already have the initial navigate URL -- kick off the navigate.
 +				LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL );
 +				mInitialNavigateURL.clear();
 +			}
 +		}
 +		
 +		if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate )
 +		{
 +			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId );
 +
 +			unsigned int rowspan = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId );
 +			unsigned int height = LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId );
 +#if !LL_QTWEBKIT_USES_PIXMAPS
 +			unsigned int buffer_size = rowspan * height;
 +#endif // !LL_QTWEBKIT_USES_PIXMAPS
 +			
 +//			std::cerr << "webkit plugin: updating" << std::endl;
 +			
 +			// TODO: should get rid of this memcpy if possible
 +			if ( mPixels && browser_pixels )
 +			{
 +//				std::cerr << "    memcopy of " << buffer_size << " bytes" << std::endl;
 +
 +#if LL_QTWEBKIT_USES_PIXMAPS
 +				// copy the pixel data upside-down because of the co-ord system
 +				for (int y=0; y<height; ++y)
 +				{
 +					memcpy( &mPixels[(height-y-1)*rowspan], &browser_pixels[y*rowspan], rowspan );
 +				}
 +#else
 +				memcpy( mPixels, browser_pixels, buffer_size );
 +#endif // LL_QTWEBKIT_USES_PIXMAPS
 +			}
 +
 +			if ( mWidth > 0 && mHeight > 0 )
 +			{
 +//				std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl;
 +				setDirty( 0, 0, mWidth, mHeight );
 +			}
 +
 +			mNeedsUpdate = false;
 +		};
 +	};
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	bool initBrowser()
 +	{
 +		// already initialized
 +		if ( mInitState > INIT_STATE_UNINITIALIZED )
 +			return true;
 +
 +		// set up directories
 +		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use
 +		if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
 +		{
 +			llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl;
 +			return false;
 +		}
 +		std::string application_dir = std::string( cwd );
 +
 +#if LL_LINUX
 +		// take care to initialize glib properly, because some
 +		// versions of Qt don't, and we indirectly need it for (some
 +		// versions of) Flash to not crash the browser.
 +		if (!g_thread_supported ()) g_thread_init (NULL);
 +		g_type_init();
 +#endif
 +
 +#if LL_DARWIN
 +		// When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on.
 +		// This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger.
 +		// This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it
 +		// which gets hit when the plugin is probed by webkit.
 +		// Unsetting the environment variable here works around this issue.
 +		unsetenv("USERBREAK");
 +#endif
 +
 +#if LL_WINDOWS
 +		//*NOTE:Mani - On windows, at least, the component path is the
 +		// location of this dll's image file. 
 +		std::string component_dir;
 +		char dll_path[_MAX_PATH];
 +		DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH);
 +		while(len && dll_path[ len ] != ('\\') )
 +		{
 +			len--;
 +		}
 +		if(len >= 0)
 +		{
 +			dll_path[len] = 0;
 +			component_dir = dll_path;
 +		}
 +		else
 +		{
 +			// *NOTE:Mani - This case should be an rare exception. 
 +			// GetModuleFileNameA should always give you a full path, no?
 +			component_dir = application_dir;
 +		}
 +#else
 +		std::string component_dir = application_dir;
 +#endif
 +
 +		// debug spam sent to viewer and displayed in the log as usual
 +		postDebugMessage( "Component dir set to: " + component_dir );
 +
 +		// window handle - needed on Windows and must be app window.
 +#if LL_WINDOWS
 +		char window_title[ MAX_PATH ];
 +		GetConsoleTitleA( window_title, MAX_PATH );
 +		void* native_window_handle = (void*)FindWindowA( NULL, window_title );
 +#else
 +		void* native_window_handle = 0;
 +#endif
 +
 +		// main browser initialization
 +		bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle );
 +		if ( result )
 +		{
 +			mInitState = INIT_STATE_INITIALIZED;
 +
 +			// debug spam sent to viewer and displayed in the log as usual
 +			postDebugMessage( "browser initialized okay" );
 +
 +			return true;
 +		};
 +
 +		// debug spam sent to viewer and displayed in the log as usual
 +		postDebugMessage( "browser nOT initialized." );
 +
 +		return false;
 +	};
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	bool initBrowserWindow()
 +	{
 +		// already initialized
 +		if ( mInitState > INIT_STATE_INITIALIZED )
 +			return true;
 +
 +		// not enough information to initialize the browser yet.
 +		if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || 
 +				mTextureWidth < 0 || mTextureHeight < 0 )
 +		{
 +			return false;
 +		};
 +		
 +		// Set up host language before creating browser window
 +		if(!mHostLanguage.empty())
 +		{
 +			LLQtWebKit::getInstance()->setHostLanguage(mHostLanguage);
 +			postDebugMessage( "Setting language to " + mHostLanguage );
 +		}
 +
 +		// turn on/off cookies based on what host app tells us
 +		LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
 +		
 +		// turn on/off plugins based on what host app tells us
 +		LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
 +
 +		// turn on/off Javascript based on what host app tells us
 +		LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
 +
 +		std::stringstream str;
 +		str << "Cookies enabled = " << mCookiesEnabled << ", plugins enabled = " << mPluginsEnabled << ", Javascript enabled = " << mJavascriptEnabled;
 +		postDebugMessage( str.str() );
 +
 +		// create single browser window
 +		mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget);
 +
 +		str.str("");
 +		str.clear();
 +		str << "Setting browser window size to " << mWidth << " x " << mHeight;
 +		postDebugMessage( str.str() );
 +
 +		// tell LLQtWebKit about the size of the browser window
 +		LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
 +
 +		// observer events that LLQtWebKit emits
 +		LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this );
 +
 +		// append details to agent string
 +		LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
 +		postDebugMessage( "Updating user agent with " + mUserAgent );
 +		
 +#if !LL_QTWEBKIT_USES_PIXMAPS
 +		// don't flip bitmap
 +		LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
 +#endif // !LL_QTWEBKIT_USES_PIXMAPS
 +
 +		// set background color
 +		// convert background color channels from [0.0, 1.0] to [0, 255];
 +		LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) );
 +
 +		// Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns.
 +		setInitState(INIT_STATE_NAVIGATING);
 +
 +		// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance.
 +		// FIXME: Re-added this because navigating to a "page" initializes things correctly - especially
 +		// for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date.
 +		// Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E"
 +		// where RRGGBB is the background color in HTML style
 +		std::stringstream url;
 +		
 +		url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#";
 +		// convert background color channels from [0.0, 1.0] to [0, 255];
 +		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f);
 +		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f);
 +		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f);
 +		url << "%22%3E%3C/body%3E%3C/html%3E";
 +		
 +		//lldebugs << "data url is: " << url.str() << llendl;
 +					
 +		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() );
 +//		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
 +
 +		return true;	
 +	}
 +
 +	void setVolume(F32 vol);
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onCursorChanged(const EventType& event)
 +	{
 +		LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue();
 +		std::string name;
 +
 +		switch(llqt_cursor)
 +		{
 +			case LLQtWebKit::C_ARROW:
 +				name = "arrow";
 +			break;
 +			case LLQtWebKit::C_IBEAM:
 +				name = "ibeam";
 +			break;
 +			case LLQtWebKit::C_SPLITV:
 +				name = "splitv";
 +			break;
 +			case LLQtWebKit::C_SPLITH:
 +				name = "splith";
 +			break;
 +			case LLQtWebKit::C_POINTINGHAND:
 +				name = "hand";
 +			break;
 +			
 +			default:
 +				llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl;
 +			break;
 +		}
 +		
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
 +		message.setValue("name", name);
 +		sendMessage(message);
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onPageChanged( const EventType& event )
 +	{
 +		if(mInitState == INIT_STATE_WAIT_REDRAW)
 +		{
 +			setInitState(INIT_STATE_WAIT_COMPLETE);
 +		}
 +		
 +		// flag that an update is required
 +		mNeedsUpdate = true;
 +	};
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onNavigateBegin(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
 +			message.setValue("uri", event.getEventUri());
 +			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
 +			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
 +			sendMessage(message);
 +
 +			// debug spam sent to viewer and displayed in the log as usual
 +			postDebugMessage( "Navigate begin event at: " + event.getEventUri() );
 +
 +			setStatus(STATUS_LOADING);
 +		}
 +
 +		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			// Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary.
 +//			setInitState(INIT_STATE_WAIT_REDRAW);
 +			setInitState(INIT_STATE_WAIT_COMPLETE);
 +		}
 +		
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onNavigateComplete(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			if(mInitState < INIT_STATE_RUNNING)
 +			{
 +				setInitState(INIT_STATE_RUNNING);
 +				
 +				// Clear the history, so the "back" button doesn't take you back to "about:blank".
 +				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
 +			}
 +			
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
 +			message.setValue("uri", event.getEventUri());
 +			message.setValueS32("result_code", event.getIntValue());
 +			message.setValue("result_string", event.getStringValue());
 +			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
 +			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
 +			sendMessage(message);
 +			
 +			setStatus(STATUS_LOADED);
 +		}
 +		else if(mInitState == INIT_STATE_NAVIGATING)
 +		{
 +			setInitState(INIT_STATE_NAVIGATE_COMPLETE);
 +		}
 +
 +		// debug spam sent to viewer and displayed in the log as usual
 +		postDebugMessage( "Navigate complete event at: " + event.getEventUri() );
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onUpdateProgress(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress");
 +			message.setValueS32("percent", event.getIntValue());
 +			sendMessage(message);
 +		}
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onStatusTextChange(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
 +			message.setValue("status", event.getStringValue());
 +			sendMessage(message);
 +		}
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onTitleChange(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
 +			message.setValue("name", event.getStringValue());
 +			sendMessage(message);
 +		}
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onNavigateErrorPage(const EventType& event)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page");
 +		message.setValueS32("status_code", event.getIntValue());
 +		sendMessage(message);
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onLocationChange(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
 +			message.setValue("uri", event.getEventUri());
 +			sendMessage(message);
 +		}
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onClickLinkHref(const EventType& event)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
 +		message.setValue("uri", event.getEventUri());
 +		message.setValue("target", event.getStringValue());
 +		message.setValue("uuid", event.getStringValue2());
 +		sendMessage(message);
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onClickLinkNoFollow(const EventType& event)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
 +		message.setValue("uri", event.getEventUri());
 +#if LLQTWEBKIT_API_VERSION >= 7
 +		message.setValue("nav_type", event.getNavigationType());
 +#else
 +		message.setValue("nav_type", "clicked");
 +#endif
 +		sendMessage(message);
 +	}
 +	
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onCookieChanged(const EventType& event)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookie_set");
 +		message.setValue("cookie", event.getStringValue());
 +		// These could be passed through as well, but aren't really needed.
 +//		message.setValue("uri", event.getEventUri());
 +//		message.setValueBoolean("dead", (event.getIntValue() != 0))
 +		sendMessage(message);
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onWindowCloseRequested(const EventType& event)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request");
 +		message.setValue("uuid", event.getStringValue());
 +		sendMessage(message);
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onWindowGeometryChangeRequested(const EventType& event)
 +	{
 +		int x, y, width, height;
 +		event.getRectValue(x, y, width, height);
 +
 +		// This sometimes gets called with a zero-size request.  Don't pass these along.
 +		if(width > 0 && height > 0)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change");
 +			message.setValue("uuid", event.getStringValue());
 +			message.setValueS32("x", x);
 +			message.setValueS32("y", y);
 +			message.setValueS32("width", width);
 +			message.setValueS32("height", height);
 +			sendMessage(message);
 +		}
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	std::string onRequestFilePicker( const EventType& eventIn )
 +	{
 +		return blockingPickFile();
 +	}
 +	
 +	std::string mAuthUsername;
 +	std::string mAuthPassword;
 +	bool mAuthOK;
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password)
 +	{
 +		mAuthOK = false;
 +
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
 +		message.setValue("url", in_url);
 +		message.setValue("realm", in_realm);
 +		message.setValueBoolean("blocking_request", true);
 +				
 +		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
 +		sendMessage(message);
 +		
 +		if(mAuthOK)
 +		{
 +			out_username = mAuthUsername;
 +			out_password = mAuthPassword;
 +		}
 +		
 +		return mAuthOK;
 +	}
 +	
 +	void authResponse(LLPluginMessage &message)
 +	{
 +		mAuthOK = message.getValueBoolean("ok");
 +		if(mAuthOK)
 +		{
 +			mAuthUsername = message.getValue("username");
 +			mAuthPassword = message.getValue("password");
 +		}
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onLinkHovered(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered");
 +			message.setValue("link", event.getEventUri());
 +			message.setValue("title", event.getStringValue());
 +			message.setValue("text", event.getStringValue2());
 +			sendMessage(message);
 +		}
 +	}
 +	
 +	LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers)
 +	{
 +		int result = 0;
 +		
 +		if(modifiers.find("shift") != std::string::npos)
 +			result |= LLQtWebKit::KM_MODIFIER_SHIFT;
 +
 +		if(modifiers.find("alt") != std::string::npos)
 +			result |= LLQtWebKit::KM_MODIFIER_ALT;
 +		
 +		if(modifiers.find("control") != std::string::npos)
 +			result |= LLQtWebKit::KM_MODIFIER_CONTROL;
 +		
 +		if(modifiers.find("meta") != std::string::npos)
 +			result |= LLQtWebKit::KM_MODIFIER_META;
 +		
 +		return (LLQtWebKit::EKeyboardModifier)result;
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers )
 +	{
 +		native_scan_code = 0;
 +		native_virtual_key = 0;
 +		native_modifiers = 0;
 +		
 +		if( native_key_data.isMap() )
 +		{
 +#if LL_DARWIN
 +			native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger());
 +			native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger());
 +			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
 +#elif LL_WINDOWS
 +			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
 +			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
 +			// TODO: I don't think we need to do anything with native modifiers here -- please verify
 +#elif LL_LINUX
 +			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
 +			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
 +			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
 +#else
 +			// Add other platforms here as needed
 +#endif
 +		};
 +	};
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
 +	{
 +		// The incoming values for 'key' will be the ones from indra_constants.h
 +		std::string utf8_text;
 +		
 +		if(key < KEY_SPECIAL)
 +		{
 +			// Low-ascii characters need to get passed through.
 +			utf8_text = (char)key;
 +		}
 +		
 +		// Any special-case handling we want to do for particular keys...
 +		switch((KEY)key)
 +		{
 +			// ASCII codes for some standard keys
 +			case LLQtWebKit::KEY_BACKSPACE:		utf8_text = (char)8;		break;
 +			case LLQtWebKit::KEY_TAB:			utf8_text = (char)9;		break;
 +			case LLQtWebKit::KEY_RETURN:		utf8_text = (char)13;		break;
 +			case LLQtWebKit::KEY_PAD_RETURN:	utf8_text = (char)13;		break;
 +			case LLQtWebKit::KEY_ESCAPE:		utf8_text = (char)27;		break;
 +			
 +			default:  
 +			break;
 +		}
 +		
 +//		std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl;
 +		
 +		uint32_t native_scan_code = 0;
 +		uint32_t native_virtual_key = 0;
 +		uint32_t native_modifiers = 0;
 +		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
 +		
 +		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
 +
 +		checkEditState();
 +	};
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
 +	{		
 +		uint32_t key = LLQtWebKit::KEY_NONE;
 +		
 +//		std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl;
 +		
 +		if(utf8str.size() == 1)
 +		{
 +			// The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character.
 +			// In this case, use it as the key value.
 +			key = utf8str[0];
 +		}
 +
 +		uint32_t native_scan_code = 0;
 +		uint32_t native_virtual_key = 0;
 +		uint32_t native_modifiers = 0;
 +		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
 +		
 +		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
 +		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
 +
 +		checkEditState();
 +	};
 +	
 +	void checkEditState(void)
 +	{
 +		bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT);
 +		bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY);
 +		bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE);
 +					
 +		if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
 +			
 +			if(can_cut != mCanCut)
 +			{
 +				mCanCut = can_cut;
 +				message.setValueBoolean("cut", can_cut);
 +			}
 +
 +			if(can_copy != mCanCopy)
 +			{
 +				mCanCopy = can_copy;
 +				message.setValueBoolean("copy", can_copy);
 +			}
 +
 +			if(can_paste != mCanPaste)
 +			{
 +				mCanPaste = can_paste;
 +				message.setValueBoolean("paste", can_paste);
 +			}
 +			
 +			sendMessage(message);
 +			
 +		}
 +	}
 +	
 +	std::string mPickedFile;
 +	
 +	std::string blockingPickFile(void)
 +	{
 +		mPickedFile.clear();
 +		
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
 +		message.setValueBoolean("blocking_request", true);
 +		
 +		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
 +		sendMessage(message);
 +		
 +		return mPickedFile;
 +	}
 +
 +	void onPickFileResponse(const std::string &file)
 +	{
 +		mPickedFile = file;
 +	}
 +
 +};
 +
 +MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
 +	MediaPluginBase(host_send_func, host_user_data)
 +{
 +//	std::cerr << "MediaPluginWebKit constructor" << std::endl;
 +
 +	mBrowserWindowId = 0;
 +	mInitState = INIT_STATE_UNINITIALIZED;
 +	mNeedsUpdate = true;
 +	mCanCut = false;
 +	mCanCopy = false;
 +	mCanPaste = false;
 +	mLastMouseX = 0;
 +	mLastMouseY = 0;
 +	mFirstFocus = true;
 +	mBackgroundR = 0.0f;
 +	mBackgroundG = 0.0f;
 +	mBackgroundB = 0.0f;
 +
 +	mHostLanguage = "en";		// default to english
 +	mJavascriptEnabled = true;	// default to on
 +	mPluginsEnabled = true;		// default to on
 +	mEnableMediaPluginDebugging = false;
 +	mUserAgent = "LLPluginMedia Web Browser";
 +}
 +
 +MediaPluginWebKit::~MediaPluginWebKit()
 +{
 +	// unhook observer
 +	LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
 +
 +	// clean up
 +	LLQtWebKit::getInstance()->reset();
 +
 +//	std::cerr << "MediaPluginWebKit destructor" << std::endl;
 +}
 +
 +void MediaPluginWebKit::receiveMessage(const char *message_string)
 +{
 +//	std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
 +	LLPluginMessage message_in;
 +	
 +	if(message_in.parse(message_string) >= 0)
 +	{
 +		std::string message_class = message_in.getClass();
 +		std::string message_name = message_in.getName();
 +		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
 +		{
 +			if(message_name == "init")
 +			{
 +				LLPluginMessage message("base", "init_response");
 +				LLSD versions = LLSD::emptyMap();
 +				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
 +				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
 +				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
 +				message.setValueLLSD("versions", versions);
 +
 +				std::string plugin_version = "Webkit media plugin, Webkit version ";
 +				plugin_version += LLQtWebKit::getInstance()->getVersion();
 +				message.setValue("plugin_version", plugin_version);
 +				sendMessage(message);
 +			}
 +			else if(message_name == "idle")
 +			{
 +				// no response is necessary here.
 +				F64 time = message_in.getValueReal("time");
 +				
 +				// Convert time to milliseconds for update()
 +				update((int)(time * 1000.0f));
 +			}
 +			else if(message_name == "cleanup")
 +			{
 +				// DTOR most likely won't be called but the recent change to the way this process
 +				// is (not) killed means we see this message and can do what we need to here.
 +				// Note: this cleanup is ultimately what writes cookies to the disk
 +				LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
 +				LLQtWebKit::getInstance()->reset();
 +			}
 +			else if(message_name == "shm_added")
 +			{
 +				SharedSegmentInfo info;
 +				info.mAddress = message_in.getValuePointer("address");
 +				info.mSize = (size_t)message_in.getValueS32("size");
 +				std::string name = message_in.getValue("name");
 +				
 +//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name 
 +//					<< ", size: " << info.mSize 
 +//					<< ", address: " << info.mAddress 
 +//					<< std::endl;
 +
 +				mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
 +			
 +			}
 +			else if(message_name == "shm_remove")
 +			{
 +				std::string name = message_in.getValue("name");
 +				
 +//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl;
 +
 +				SharedSegmentMap::iterator iter = mSharedSegments.find(name);
 +				if(iter != mSharedSegments.end())
 +				{
 +					if(mPixels == iter->second.mAddress)
 +					{
 +						// This is the currently active pixel buffer.  Make sure we stop drawing to it.
 +						mPixels = NULL;
 +						mTextureSegmentName.clear();
 +					}
 +					mSharedSegments.erase(iter);
 +				}
 +				else
 +				{
 +//					std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
 +				}
 +
 +				// Send the response so it can be cleaned up.
 +				LLPluginMessage message("base", "shm_remove_response");
 +				message.setValue("name", name);
 +				sendMessage(message);
 +			}
 +			else
 +			{
 +//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
 +			}
 +		}
 +		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
 +		{
 +			if(message_name == "set_volume")
 +			{
 +				F32 volume = message_in.getValueReal("volume");
 +				setVolume(volume);
 +			}
 +		}
 +		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
 +		{
 +			if(message_name == "init")
 +			{
 +				mTarget = message_in.getValue("target");
 +				
 +				// This is the media init message -- all necessary data for initialization should have been received.
 +				if(initBrowser())
 +				{
 +					
 +					// Plugin gets to decide the texture parameters to use.
 +					mDepth = 4;
 +
 +					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
 +					message.setValueS32("default_width", 1024);
 +					message.setValueS32("default_height", 1024);
 +					message.setValueS32("depth", mDepth);
 +					message.setValueU32("internalformat", GL_RGBA);
 +	#if LL_QTWEBKIT_USES_PIXMAPS
 +					message.setValueU32("format", GL_BGRA_EXT); // I hope this isn't system-dependant... is it?  If so, we'll have to check the root window's pixel layout or something... yuck.
 +	#else
 +					message.setValueU32("format", GL_RGBA);
 +	#endif // LL_QTWEBKIT_USES_PIXMAPS
 +					message.setValueU32("type", GL_UNSIGNED_BYTE);
 +					message.setValueBoolean("coords_opengl", true);
 +					sendMessage(message);
 +				}
 +				else
 +				{
 +					// if initialization failed, we're done.
 +					mDeleteMe = true;
 +				}
 +
 +			}
 +			else if(message_name == "set_user_data_path")
 +			{
 +				std::string user_data_path = message_in.getValue("path"); // n.b. always has trailing platform-specific dir-delimiter
 +				mProfileDir = user_data_path + "browser_profile";
 +
 +				// FIXME: Should we do anything with this if it comes in after the browser has been initialized?
 +			}
 +			else if(message_name == "set_language_code")
 +			{
 +				mHostLanguage = message_in.getValue("language");
 +
 +				// FIXME: Should we do anything with this if it comes in after the browser has been initialized?
 +			}
 +			else if(message_name == "plugins_enabled")
 +			{
 +				mPluginsEnabled = message_in.getValueBoolean("enable");
 +			}
 +			else if(message_name == "javascript_enabled")
 +			{
 +				mJavascriptEnabled = message_in.getValueBoolean("enable");
 +			}
 +			else if(message_name == "size_change")
 +			{
 +				std::string name = message_in.getValue("name");
 +				S32 width = message_in.getValueS32("width");
 +				S32 height = message_in.getValueS32("height");
 +				S32 texture_width = message_in.getValueS32("texture_width");
 +				S32 texture_height = message_in.getValueS32("texture_height");
 +				mBackgroundR = message_in.getValueReal("background_r");
 +				mBackgroundG = message_in.getValueReal("background_g");
 +				mBackgroundB = message_in.getValueReal("background_b");
 +//				mBackgroundA = message_in.setValueReal("background_a");		// Ignore any alpha
 +								
 +				if(!name.empty())
 +				{
 +					// Find the shared memory region with this name
 +					SharedSegmentMap::iterator iter = mSharedSegments.find(name);
 +					if(iter != mSharedSegments.end())
 +					{
 +						mPixels = (unsigned char*)iter->second.mAddress;
 +						mWidth = width;
 +						mHeight = height;
 +
 +						if(initBrowserWindow())
 +						{
 +
 +							// size changed so tell the browser
 +							LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
 +							
 +	//						std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight 
 +	//								<< ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl;
 +									
 +							S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); 
 +							
 +							// The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response.
 +							if(real_width <= texture_width)
 +							{
 +								texture_width = real_width;
 +							}
 +							else
 +							{
 +								// This won't work -- it'll be bigger than the allocated memory.  This is a fatal error.
 +	//							std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl;
 +								mDeleteMe = true;
 +								return;
 +							}
 +						}
 +						else
 +						{
 +							// Setting up the browser window failed.  This is a fatal error.
 +							mDeleteMe = true;
 +						}
 +
 +						
 +						mTextureWidth = texture_width;
 +						mTextureHeight = texture_height;
 +						
 +					};
 +				};
 +
 +				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
 +				message.setValue("name", name);
 +				message.setValueS32("width", width);
 +				message.setValueS32("height", height);
 +				message.setValueS32("texture_width", texture_width);
 +				message.setValueS32("texture_height", texture_height);
 +				sendMessage(message);
 +
 +			}
 +			else if(message_name == "load_uri")
 +			{
 +				std::string uri = message_in.getValue("uri");
 +
 +//				std::cout << "loading URI: " << uri << std::endl;
 +				
 +				if(!uri.empty())
 +				{
 +					if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +					{
 +						LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri );
 +					}
 +					else
 +					{
 +						mInitialNavigateURL = uri;
 +					}
 +				}
 +			}
 +			else if(message_name == "mouse_event")
 +			{
 +				std::string event = message_in.getValue("event");
 +				S32 button = message_in.getValueS32("button");
 +				mLastMouseX = message_in.getValueS32("x");
 +				mLastMouseY = message_in.getValueS32("y");
 +				std::string modifiers = message_in.getValue("modifiers");
 +				
 +				// Treat unknown mouse events as mouse-moves.
 +				LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE;
 +				if(event == "down")
 +				{
 +					mouse_event = LLQtWebKit::ME_MOUSE_DOWN;
 +				}
 +				else if(event == "up")
 +				{
 +					mouse_event = LLQtWebKit::ME_MOUSE_UP;
 +				}
 +				else if(event == "double_click")
 +				{
 +					mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK;
 +				}
 +				
 +				LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers));
 +				checkEditState();
 +			}
 +			else if(message_name == "scroll_event")
 +			{
 +				S32 x = message_in.getValueS32("x");
 +				S32 y = message_in.getValueS32("y");
 +				std::string modifiers = message_in.getValue("modifiers");
 +				
 +				// Incoming scroll events are adjusted so that 1 detent is approximately 1 unit.
 +				// Qt expects 1 detent to be 120 units.
 +				// It also seems that our y scroll direction is inverted vs. what Qt expects.
 +				
 +				x *= 120;
 +				y *= -120;
 +				
 +				LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers));
 +			}
 +			else if(message_name == "key_event")
 +			{
 +				std::string event = message_in.getValue("event");
 +				S32 key = message_in.getValueS32("key");
 +				std::string modifiers = message_in.getValue("modifiers");
 +				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
 +				
 +				// Treat unknown events as key-up for safety.
 +				LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP;
 +				if(event == "down")
 +				{
 +					key_event = LLQtWebKit::KE_KEY_DOWN;
 +				}
 +				else if(event == "repeat")
 +				{
 +					key_event = LLQtWebKit::KE_KEY_REPEAT;
 +				}
 +				
 +				keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data);
 +			}
 +			else if(message_name == "text_event")
 +			{
 +				std::string text = message_in.getValue("text");
 +				std::string modifiers = message_in.getValue("modifiers");
 +				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
 +				
 +				unicodeInput(text, decodeModifiers(modifiers), native_key_data);
 +			}
 +			if(message_name == "edit_cut")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT );
 +				checkEditState();
 +			}
 +			if(message_name == "edit_copy")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY );
 +				checkEditState();
 +			}
 +			if(message_name == "edit_paste")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE );
 +				checkEditState();
 +			}
 +			if(message_name == "pick_file_response")
 +			{
 +				onPickFileResponse(message_in.getValue("file"));
 +			}
 +			if(message_name == "auth_response")
 +			{
 +				authResponse(message_in);
 +			}
 +			else
 +			if(message_name == "enable_media_plugin_debugging")
 +			{
 +				mEnableMediaPluginDebugging = message_in.getValueBoolean( "enable" );
 +			}
 +
 +			else
 +			if(message_name == "js_enable_object")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				bool enable = message_in.getValueBoolean( "enable" );
 +				LLQtWebKit::getInstance()->setSLObjectEnabled( enable );
 +#endif
 +			}
 +			else
 +			if(message_name == "js_agent_location")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				F32 x = message_in.getValueReal("x");
 +				F32 y = message_in.getValueReal("y");
 +				F32 z = message_in.getValueReal("z");
 +				LLQtWebKit::getInstance()->setAgentLocation( x, y, z );
 +				LLQtWebKit::getInstance()->emitLocation();
 +#endif
 +			}
 +			else
 +			if(message_name == "js_agent_global_location")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				F32 x = message_in.getValueReal("x");
 +				F32 y = message_in.getValueReal("y");
 +				F32 z = message_in.getValueReal("z");
 +				LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z );
 +				LLQtWebKit::getInstance()->emitLocation();
 +#endif
 +			}
 +			else			
 +			if(message_name == "js_agent_orientation")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				F32 angle = message_in.getValueReal("angle");
 +				LLQtWebKit::getInstance()->setAgentOrientation( angle );
 +				LLQtWebKit::getInstance()->emitLocation();
 +#endif
 +			}
 +			else
 +			if(message_name == "js_agent_region")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				const std::string& region = message_in.getValue("region");
 +				LLQtWebKit::getInstance()->setAgentRegion( region );
 +				LLQtWebKit::getInstance()->emitLocation();
 +#endif
 +			}
 +			else
 +				if(message_name == "js_agent_maturity")
 +				{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +					const std::string& maturity = message_in.getValue("maturity");
 +					LLQtWebKit::getInstance()->setAgentMaturity( maturity );
 +					LLQtWebKit::getInstance()->emitMaturity();
 +#endif
 +				}
 +			else
 +			if(message_name == "js_agent_language")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				const std::string& language = message_in.getValue("language");
 +				LLQtWebKit::getInstance()->setAgentLanguage( language );
 +				LLQtWebKit::getInstance()->emitLanguage();
 +#endif
 +			}
 +			else
 +			{
 +//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
 +			}
 +		}
 +		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
 +		{
 +			if(message_name == "focus")
 +			{
 +				bool val = message_in.getValueBoolean("focused");
 +				LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val );
 +				
 +				if(mFirstFocus && val)
 +				{
 +					// On the first focus, post a tab key event.  This fixes a problem with initial focus.
 +					std::string empty;
 +					keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty));
 +					keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty));
 +					mFirstFocus = false;
 +				}
 +			}
 +			else if(message_name == "clear_cache")
 +			{
 +				LLQtWebKit::getInstance()->clearCache();
 +			}
 +			else if(message_name == "clear_cookies")
 +			{
 +				LLQtWebKit::getInstance()->clearAllCookies();
 +			}
 +			else if(message_name == "enable_cookies")
 +			{
 +				mCookiesEnabled = message_in.getValueBoolean("enable");
 +				LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
 +			}
 +			else if(message_name == "enable_plugins")
 +			{
 +				mPluginsEnabled = message_in.getValueBoolean("enable");
 +				LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
 +			}
 +			else if(message_name == "enable_javascript")
 +			{
 +				mJavascriptEnabled = message_in.getValueBoolean("enable");
 +				//LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
 +			}
 +			else if(message_name == "set_cookies")
 +			{
 +				LLQtWebKit::getInstance()->setCookies(message_in.getValue("cookies"));
 +			}
 +			else if(message_name == "proxy_setup")
 +			{
 +				bool val = message_in.getValueBoolean("enable");
 +				std::string host = message_in.getValue("host");
 +				int port = message_in.getValueS32("port");
 +				LLQtWebKit::getInstance()->enableProxy( val, host, port );
 +			}
 +			else if(message_name == "browse_stop")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP );
 +			}
 +			else if(message_name == "browse_reload")
 +			{
 +				// foo = message_in.getValueBoolean("ignore_cache");
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD );
 +			}
 +			else if(message_name == "browse_forward")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD );
 +			}
 +			else if(message_name == "browse_back")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK );
 +			}
 +			else if(message_name == "set_status_redirect")
 +			{
 +				int code = message_in.getValueS32("code");
 +				std::string url = message_in.getValue("url");
 +				if ( 404 == code )	// browser lib only supports 404 right now
 +				{
 +#if LLQTWEBKIT_API_VERSION < 8
 +				 	LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
 +#endif
 +				};
 +			}
 +			else if(message_name == "set_user_agent")
 +			{
 +				mUserAgent = message_in.getValue("user_agent");
 +				LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
 +			}
 +			else if(message_name == "show_web_inspector")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 10
 +				bool val = message_in.getValueBoolean("show");
 +				LLQtWebKit::getInstance()->showWebInspector( val );
 +#else
 +				llwarns << "Ignoring showWebInspector message (llqtwebkit version is too old)." << llendl;
 +#endif
 +			}
 +			else if(message_name == "ignore_ssl_cert_errors")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 3
 +				LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") );
 +#else
 +				llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl;
 +#endif
 +			}
 +			else if(message_name == "add_certificate_file_path")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 6
 +				LLQtWebKit::getInstance()->setCAFile( message_in.getValue("path") );
 +#else
 +				llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl;
 +#endif
 +			}
 +			else if(message_name == "init_history")
 +			{
 +				// Initialize browser history
 +				LLSD history = message_in.getValueLLSD("history");
 +				// First, clear the URL history
 +				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
 +				// Then, add the history items in order
 +				LLSD::array_iterator iter_history = history.beginArray();
 +				LLSD::array_iterator end_history = history.endArray();
 +				for(; iter_history != end_history; ++iter_history)
 +				{
 +					std::string url = (*iter_history).asString();
 +					if(! url.empty()) {
 +						LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url);
 +					}
 +				}
 +			}
 +			else if(message_name == "proxy_window_opened")
 +			{
 +				std::string target = message_in.getValue("target");
 +				std::string uuid = message_in.getValue("uuid");
 +				LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid);
 +			}
 +			else if(message_name == "proxy_window_closed")
 +			{
 +				std::string uuid = message_in.getValue("uuid");
 +				LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid);
 +			}
 +			else
 +			{
 +//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;
 +			};
 +		}
 +		else
 +		{
 +//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
 +		};
 +	}
 +}
 +
 +void MediaPluginWebKit::setVolume(F32 volume)
 +{
 +	mVolumeCatcher.setVolume(volume);
 +}
 +
 +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
 +{
 +	MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data);
 +	*plugin_send_func = MediaPluginWebKit::staticReceiveMessage;
 +	*plugin_user_data = (void*)self;
 +
 +	return 0;
 +}
 +
 +
 diff --git a/indra/newview/app_settings/CA.pem b/indra/newview/app_settings/CA.pem index 6140842a7f..a16b4225e5 100644 --- a/indra/newview/app_settings/CA.pem +++ b/indra/newview/app_settings/CA.pem @@ -4587,38 +4587,6 @@ zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy  wy39FCqQmbkHzJ8=  -----END CERTIFICATE-----  -----BEGIN CERTIFICATE----- -MIIFijCCA3KgAwIBAgIQDHbanJEMTiye/hXQWJM8TDANBgkqhkiG9w0BAQUFADBf -MQswCQYDVQQGEwJOTDESMBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdp -Tm90YXIgUm9vdCBDQTEgMB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmww -HhcNMDcwNTE2MTcxOTM2WhcNMjUwMzMxMTgxOTIxWjBfMQswCQYDVQQGEwJOTDES -MBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdpTm90YXIgUm9vdCBDQTEg -MB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmwwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCssFjBAL3YIQgLK5r+blYwBZ8bd5AQQVzDDYcRd46B -8cp86Yxq7Th0Nbva3/m7wAk3tJZzgX0zGpg595NvlX89ubF1h7pRSOiLcD6VBMXY -tsMW2YiwsYcdcNqGtA8Ui3rPENF0NqISe3eGSnnme98CEWilToauNFibJBN4ViIl -HgGLS1Fx+4LMWZZpiFpoU8W5DQI3y0u8ZkqQfioLBQftFl9VkHXYRskbg+IIvvEj -zJkd1ioPgyAVWCeCLvriIsJJsbkBgWqdbZ1Ad2h2TiEqbYRAhU52mXyC8/O3AlnU -JgEbjt+tUwbRrhjd4rI6y9eIOI6sWym5GdOY+RgDz0iChmYLG2kPyes4iHomGgVM -ktck1JbyrFIto0fVUvY//s6EBnCmqj6i8rZWNBhXouSBbefK8GrTx5FrAoNBfBXv -a5pkXuPQPOWx63tdhvvL5ndJzaNl3Pe5nLjkC1+Tz8wwGjIczhxjlaX56uF0i57p -K6kwe6AYHw4YC+VbqdPRbB4HZ4+RS6mKvNJmqpMBiLKR+jFc1abBUggJzQpjotMi -puih2TkGl/VujQKQjBR7P4DNG5y6xFhyI6+2Vp/GekIzKQc/gsnmHwUNzUwoNovT -yD4cxojvXu6JZOkd69qJfjKmadHdzIif0dDJZiHcBmfFlHqabWJMfczgZICynkeO -owIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV -HQ4EFgQUiGi/4I41xDs4a2L3KDuEgcgM100wDQYJKoZIhvcNAQEFBQADggIBADsC -jcs8MOhuoK3yc7NfniUTBAXT9uOLuwt5zlPe5JbF0a9zvNXD0EBVfEB/zRtfCdXy -fJ9oHbtdzno5wozWmHvFg1Wo1X1AyuAe94leY12hE8JdiraKfADzI8PthV9xdvBo -Y6pFITlIYXg23PFDk9Qlx/KAZeFTAnVR/Ho67zerhChXDNjU1JlWbOOi/lmEtDHo -M/hklJRRl6s5xUvt2t2AC298KQ3EjopyDedTFLJgQT2EkTFoPSdE2+Xe9PpjRchM -Ppj1P0G6Tss3DbpmmPHdy59c91Q2gmssvBNhl0L4eLvMyKKfyvBovWsdst+Nbwed -2o5nx0ceyrm/KkKRt2NTZvFCo+H0Wk1Ya7XkpDOtXHAd3ODy63MUkZoDweoAZbwH -/M8SESIsrqC9OuCiKthZ6SnTGDWkrBFfGbW1G/8iSlzGeuQX7yCpp/Q/rYqnmgQl -nQ7KN+ZQ/YxCKQSa7LnPS3K94gg2ryMvYuXKAdNw23yCIywWMQzGNgeQerEfZ1jE -O1hZibCMjFCz2IbLaKPECudpSyDOwR5WS5WpI2jYMNjD67BVUc3l/Su49bsRn1NU -9jQZjHkJNsphFyUXC4KYcwx3dMPVDceoEkzHp1RxRy4sGn3J4ys7SN4nhKdjNrN9 -j6BkOSQNPXuHr2ZcdBtLc7LljPCGmbjlxd+Ewbfr ------END CERTIFICATE----- ------BEGIN CERTIFICATE-----  MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO  TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh  dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 43aa67e949..6ebb0162a4 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -25,7 +25,7 @@        <key>Type</key>        <string>S32</string>        <key>Value</key> -      <real>300</real> +      <real>0</real>      </map>      <key>AdminMenu</key>      <map> @@ -1981,6 +1981,17 @@        <key>Value</key>        <integer>0</integer>      </map> +    <key>DebugShowPrivateMem</key> +    <map> +      <key>Comment</key> +      <string>Show Private Mem Info</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map>      <key>DebugShowRenderInfo</key>      <map>        <key>Comment</key> @@ -5459,6 +5470,17 @@        <key>Value</key>        <real>48.0</real>      </map> +    <key>MaxHeapSize</key> +    <map> +      <key>Comment</key> +      <string>Maximum heap size (GB)</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>1.6</real> +    </map>      <key>MaxSelectDistance</key>      <map>        <key>Comment</key> @@ -5481,6 +5503,17 @@        <key>Value</key>        <real>60.0</real>      </map> +  <key>MediaPluginDebugging</key> +  <map> +    <key>Comment</key> +    <string>Turn on debugging messages that may help diagnosing media issues (WARNING: May reduce performance).</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>0</integer> +  </map>    <key>MediaControlFadeTime</key>    <map>      <key>Comment</key> @@ -5580,6 +5613,17 @@      <key>Value</key>      <integer>1</integer>    </map> +  <key>MemoryFailurePreventionEnabled</key> +  <map> +    <key>Comment</key> +    <string>If set, the viewer will quit to avoid crash when memory failure happens</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>0</integer> +  </map>    <key>MemoryLogFrequency</key>          <map>          <key>Comment</key> @@ -5591,6 +5635,17 @@          <key>Value</key>              <real>600.0</real>          </map> +    <key>MemoryPrivatePoolEnabled</key> +    <map> +      <key>Comment</key> +      <string>Enable the private memory pool management</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map>      <key>MemProfiling</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 1388d9aee0..a0af94ba77 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2285,7 +2285,9 @@ void LLAppearanceMgr::autopopulateOutfits()  void LLAppearanceMgr::onFirstFullyVisible()  {  	gAgentAvatarp->debugAvatarVisible(); -	autopopulateOutfits(); +	// The auto-populate is failing at the point of generating outfits
 +	// folders, so don't do the library copy until that is resolved.
 +	// autopopulateOutfits();  }  bool LLAppearanceMgr::updateBaseOutfit() diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6a808b5daf..7e597fe5dc 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -686,7 +686,7 @@ LLAppViewer::~LLAppViewer()  }  bool LLAppViewer::init() -{ +{	  	//  	// Start of the application  	// @@ -719,6 +719,11 @@ bool LLAppViewer::init()  	LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; +	//set the max heap size. +	initMaxHeapSize() ; + +	LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled")) ; +  	// write Google Breakpad minidump files to our log directory  	std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");  	logdir += gDirUtilp->getDirDelimiter(); @@ -1088,9 +1093,97 @@ bool LLAppViewer::init()  	LLAgentLanguage::init(); +	return true; +} +void LLAppViewer::initMaxHeapSize() +{ +	//set the max heap size. +	//here is some info regarding to the max heap size: +	//------------------------------------------------------------------------------------------ +	// OS       | setting | SL address bits | max manageable memory space | max heap size +	// Win 32   | default | 32-bit          | 2GB                         | < 1.7GB +	// Win 32   | /3G     | 32-bit          | 3GB                         | < 1.7GB or 2.7GB +	//Linux 32  | default | 32-bit          | 3GB                         | < 2.7GB +	//Linux 32  |HUGEMEM  | 32-bit          | 4GB                         | < 3.7GB +	//64-bit OS |default  | 32-bit          | 4GB                         | < 3.7GB +	//64-bit OS |default  | 64-bit          | N/A (> 4GB)                 | N/A (> 4GB) +	//------------------------------------------------------------------------------------------ +	//currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB. + +	//F32 max_heap_size_gb = llmin(1.6f, (F32)gSavedSettings.getF32("MaxHeapSize")) ; +	F32 max_heap_size_gb = gSavedSettings.getF32("MaxHeapSize") ; +	BOOL enable_mem_failure_prevention = (BOOL)gSavedSettings.getBOOL("MemoryFailurePreventionEnabled") ; + +	LLMemory::initMaxHeapSizeGB(max_heap_size_gb, enable_mem_failure_prevention) ; +} -	return true; +void LLAppViewer::checkMemory() +{ +	const static F32 MEMORY_CHECK_INTERVAL = 1.0f ; //second +	//const static F32 MAX_QUIT_WAIT_TIME = 30.0f ; //seconds +	const static U32 MAX_SIZE_CHECKED_MEMORY_BLOCK = 64 * 1024 * 1024 ; //64 MB +	//static F32 force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ; +	static void* last_reserved_address = NULL ; + +	if(MEMORY_CHECK_INTERVAL > mMemCheckTimer.getElapsedTimeF32()) +	{ +		return ; +	} +	mMemCheckTimer.reset() ; + +	if(gGLManager.mDebugGPU) +	{ +		//update the availability of memory +		LLMemory::updateMemoryInfo() ; +	} + +	//check the virtual address space fragmentation +	if(!last_reserved_address) +	{ +		last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; +	} +	else +	{ +		last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; +		if(!last_reserved_address) //failed, try once more +		{ +			last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; +		} +	} + +	S32 is_low = !last_reserved_address || LLMemory::isMemoryPoolLow() ; + +	//if(is_low < 0) //to force quit +	//{ +	//	if(force_quit_timer > MAX_QUIT_WAIT_TIME) //just hit the limit for the first time +	//	{ +	//		//send out the notification to tell the viewer is about to quit in 30 seconds. +	//		LLNotification::Params params("ForceQuitDueToLowMemory"); +	//		LLNotifications::instance().add(params); + +	//		force_quit_timer = MAX_QUIT_WAIT_TIME - MEMORY_CHECK_INTERVAL ; +	//	} +	//	else +	//	{ +	//		force_quit_timer -= MEMORY_CHECK_INTERVAL ; +	//		if(force_quit_timer < 0.f) +	//		{ +	//			forceQuit() ; //quit +	//		} +	//	} +	//} +	//else +	//{ +	//	force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ; +	//} + +	LLPipeline::throttleNewMemoryAllocation(!is_low ? FALSE : TRUE) ;		 +	 +	if(is_low) +	{ +		LLMemory::logMemoryInfo() ; +	}  }  static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages"); @@ -1118,7 +1211,7 @@ bool LLAppViewer::mainLoop()  	//-------------------------------------------  	// Create IO Pump to use for HTTP Requests. -	gServicePump = new LLPumpIO(gAPRPoolp); +	gServicePump = new LLPumpIO;  	LLHTTPClient::setPump(*gServicePump);  	LLCurl::setCAFile(gDirUtilp->getCAFile()); @@ -1128,7 +1221,6 @@ bool LLAppViewer::mainLoop()  	LLVoiceClient::getInstance()->init(gServicePump);  	LLTimer frameTimer,idleTimer;  	LLTimer debugTime; -	LLFrameTimer memCheckTimer;  	LLViewerJoystick* joystick(LLViewerJoystick::getInstance());  	joystick->setNeedsReset(true); @@ -1139,7 +1231,9 @@ bool LLAppViewer::mainLoop()      // point of posting.      LLSD newFrame; -	const F32 memory_check_interval = 1.0f ; //second +	//LLPrivateMemoryPoolTester::getInstance()->run(false) ; +	//LLPrivateMemoryPoolTester::getInstance()->run(true) ; +	//LLPrivateMemoryPoolTester::destroy() ;  	// Handle messages  	while (!LLApp::isExiting()) @@ -1150,18 +1244,8 @@ bool LLAppViewer::mainLoop()  		llclearcallstacks;  		//check memory availability information -		{ -			if(memory_check_interval < memCheckTimer.getElapsedTimeF32()) -			{ -				memCheckTimer.reset() ; - -				//update the availability of memory -				LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ; -			} -			llcallstacks << "Available physical mem(KB): " << mAvailPhysicalMemInKB << llcallstacksendl ; -			llcallstacks << "Available virtual mem(KB): " << mAvailVirtualMemInKB << llcallstacksendl ; -		} - +		checkMemory() ; +		  		try  		{  			pingMainloopTimeout("Main:MiscNativeWindowEvents"); @@ -1325,7 +1409,7 @@ bool LLAppViewer::mainLoop()  				idleTimer.reset();  				bool is_slow = (frameTimer.getElapsedTimeF64() > FRAME_SLOW_THRESHOLD) ;  				S32 total_work_pending = 0; -				S32 total_io_pending = 0;				 +				S32 total_io_pending = 0;	  				while(!is_slow)//do not unpause threads if the frame rates are very low.  				{  					S32 work_pending = 0; @@ -1393,15 +1477,7 @@ bool LLAppViewer::mainLoop()  		}  		catch(std::bad_alloc)  		{			 -			{ -				llinfos << "Availabe physical memory(KB) at the beginning of the frame: " << mAvailPhysicalMemInKB << llendl ; -				llinfos << "Availabe virtual memory(KB) at the beginning of the frame: " << mAvailVirtualMemInKB << llendl ; - -				LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ; - -				llinfos << "Current availabe physical memory(KB): " << mAvailPhysicalMemInKB << llendl ; -				llinfos << "Current availabe virtual memory(KB): " << mAvailVirtualMemInKB << llendl ; -			} +			LLMemory::logMemoryInfo(TRUE) ;  			//stop memory leaking simulation  			LLFloaterMemLeak* mem_leak_instance = @@ -1494,16 +1570,16 @@ bool LLAppViewer::cleanup()  	}  	// *TODO - generalize this and move DSO wrangling to a helper class -brad -	std::set<struct apr_dso_handle_t *>::const_iterator i; -	for(i = mPlugins.begin(); i != mPlugins.end(); ++i) +	for(std::map<apr_dso_handle_t*, boost::shared_ptr<LLAPRPool> >::iterator plugin = mPlugins.begin(); +		plugin != mPlugins.end(); ++plugin)  	{  		int (*ll_plugin_stop_func)(void) = NULL; -		apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, *i, "ll_plugin_stop"); +		apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, plugin->first, "ll_plugin_stop");  		ll_plugin_stop_func(); -		rv = apr_dso_unload(*i); +		rv = apr_dso_unload(plugin->first);  	} -	mPlugins.clear(); +	mPlugins.clear();	// Forget handles and destroy all memory pools.  	//flag all elements as needing to be destroyed immediately  	// to ensure shutdown order @@ -1887,6 +1963,9 @@ bool LLAppViewer::cleanup()  	LLMainLoopRepeater::instance().stop(); +	//release all private memory pools. +	LLPrivateMemoryPoolManager::destroyClass() ; +  	ll_close_fail_log();  	MEM_TRACK_RELEASE @@ -1938,7 +2017,7 @@ bool LLAppViewer::initThreads()  	if (LLFastTimer::sLog || LLFastTimer::sMetricLog)  	{ -		LLFastTimer::sLogLock = new LLMutex(NULL); +		LLFastTimer::sLogLock = new LLMutex;  		mFastTimerLogThread = new LLFastTimerLogThread(LLFastTimer::sLogName);  		mFastTimerLogThread->start();  	} @@ -3186,8 +3265,7 @@ void LLAppViewer::handleViewerCrash()  		else crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,ERROR_MARKER_FILE_NAME);  		llinfos << "Creating crash marker file " << crash_file_name << llendl; -		LLAPRFile crash_file ; -		crash_file.open(crash_file_name, LL_APR_W); +		LLAPRFile crash_file(crash_file_name, LL_APR_W);  		if (crash_file.getFileHandle())  		{  			LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL; @@ -3251,11 +3329,10 @@ bool LLAppViewer::anotherInstanceRunning()  	LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;  	//Freeze case checks -	if (LLAPRFile::isExist(marker_file, NULL, LL_APR_RB)) +	if (LLAPRFile::isExist(marker_file, LL_APR_RB))  	{  		// File exists, try opening with write permissions -		LLAPRFile outfile ; -		outfile.open(marker_file, LL_APR_WB); +		LLAPRFile outfile(marker_file, LL_APR_WB);  		apr_file_t* fMarker = outfile.getFileHandle() ;   		if (!fMarker)  		{ @@ -3294,25 +3371,25 @@ void LLAppViewer::initMarkerFile()  	std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);  	std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); -	if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning()) +	if (LLAPRFile::isExist(mMarkerFileName, LL_APR_RB) && !anotherInstanceRunning())  	{  		gLastExecEvent = LAST_EXEC_FROZE;  		LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL;  	}     -	if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) +	if(LLAPRFile::isExist(logout_marker_file, LL_APR_RB))  	{  		gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;  		LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;  		LLAPRFile::remove(logout_marker_file);  	} -	if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) +	if(LLAPRFile::isExist(llerror_marker_file, LL_APR_RB))  	{  		if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;  		else gLastExecEvent = LAST_EXEC_LLERROR_CRASH;  		LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;  		LLAPRFile::remove(llerror_marker_file);  	} -	if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) +	if(LLAPRFile::isExist(error_marker_file, LL_APR_RB))  	{  		if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;  		else gLastExecEvent = LAST_EXEC_OTHER_CRASH; @@ -3328,7 +3405,7 @@ void LLAppViewer::initMarkerFile()  	// Create the marker file for this execution & lock it  	apr_status_t s; -	s = mMarkerFile.open(mMarkerFileName, LL_APR_W, TRUE);	 +	s = mMarkerFile.open(mMarkerFileName, LL_APR_W, LLAPRFile::long_lived);  	if (s == APR_SUCCESS && mMarkerFile.getFileHandle())  	{ @@ -4586,8 +4663,7 @@ void LLAppViewer::sendLogoutRequest()  		gLogoutInProgress = TRUE;  		mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME); -		LLAPRFile outfile ; -		outfile.open(mLogoutMarkerFileName, LL_APR_W); +		LLAPRFile outfile(mLogoutMarkerFileName, LL_APR_W);  		mLogoutMarkerFile =  outfile.getFileHandle() ;  		if (mLogoutMarkerFile)  		{ @@ -5039,14 +5115,15 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)  	}  #endif // LL_WINDOWS -	apr_dso_handle_t * eventhost_dso_handle = NULL; -	apr_pool_t * eventhost_dso_memory_pool = NULL; +	boost::shared_ptr<LLAPRPool> eventhost_dso_memory_pool_ptr(new LLAPRPool); +	LLAPRPool& eventhost_dso_memory_pool(*eventhost_dso_memory_pool_ptr); +	apr_dso_handle_t* eventhost_dso_handle = NULL;  	//attempt to load the shared library -	apr_pool_create(&eventhost_dso_memory_pool, NULL); +	eventhost_dso_memory_pool.create();  	apr_status_t rv = apr_dso_load(&eventhost_dso_handle,  		dso_path.c_str(), -		eventhost_dso_memory_pool); +		eventhost_dso_memory_pool());  	llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));  	llassert_always(eventhost_dso_handle != NULL); @@ -5066,7 +5143,8 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)  		llerrs << "problem loading eventhost plugin, status: " << status << llendl;  	} -	mPlugins.insert(eventhost_dso_handle); +	// Store the handle and link it to the pool that was used to allocate it. +	mPlugins[eventhost_dso_handle] = eventhost_dso_memory_pool_ptr;  }  void LLAppViewer::launchUpdater() diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 32115e0e7b..168aaf5d94 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -170,7 +170,7 @@ public:  	// mute/unmute the system's master audio  	virtual void setMasterSystemAudioMute(bool mute); -	virtual bool getMasterSystemAudioMute(); +	virtual bool getMasterSystemAudioMute();	  	// Metrics policy helper statics.  	static void metricsUpdateRegion(U64 region_handle); @@ -193,11 +193,12 @@ protected:  private: +	void initMaxHeapSize();  	bool initThreads(); // Initialize viewer threads, return false on failure.  	bool initConfiguration(); // Initialize settings from the command line/config file.  	void initUpdater(); // Initialize the updater service.  	bool initCache(); // Initialize local client cache. - +	void checkMemory() ;  	// We have switched locations of both Mac and Windows cache, make sure  	// files migrate and old cache is cleared out. @@ -269,10 +270,9 @@ private:      LLAllocator mAlloc; -	std::set<struct apr_dso_handle_t*> mPlugins; +	std::map<apr_dso_handle_t*, boost::shared_ptr<LLAPRPool> > mPlugins; -	U32 mAvailPhysicalMemInKB ; -	U32 mAvailVirtualMemInKB ; +	LLFrameTimer mMemCheckTimer;  	boost::scoped_ptr<LLUpdaterService> mUpdater; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 48d02dfeaa..db11462fcb 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -111,6 +111,7 @@ int main( int argc, char **argv )  	}  	delete viewer_app_ptr;  	viewer_app_ptr = NULL; +  	return 0;  } diff --git a/indra/newview/llappviewerlinux_api_dbus.cpp b/indra/newview/llappviewerlinux_api_dbus.cpp index 32e7e0a83d..1ae469dfcf 100644 --- a/indra/newview/llappviewerlinux_api_dbus.cpp +++ b/indra/newview/llappviewerlinux_api_dbus.cpp @@ -27,11 +27,11 @@  #if LL_DBUS_ENABLED  #include "linden_common.h" +#include "llaprpool.h"  extern "C" {  #include <dbus/dbus-glib.h> -#include "apr_pools.h"  #include "apr_dso.h"  } @@ -44,7 +44,7 @@ extern "C" {  #undef LL_DBUS_SYM  static bool sSymsGrabbed = false; -static apr_pool_t *sSymDBUSDSOMemoryPool = NULL; +static LLAPRPool sSymDBUSDSOMemoryPool;  static apr_dso_handle_t *sSymDBUSDSOHandleG = NULL;  bool grab_dbus_syms(std::string dbus_dso_name) @@ -63,11 +63,11 @@ bool grab_dbus_syms(std::string dbus_dso_name)  #define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##DBUSSYM, sSymDBUSDSOHandle, #DBUSSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #DBUSSYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #DBUSSYM, (void*)ll##DBUSSYM);}while(0)  	//attempt to load the shared library -	apr_pool_create(&sSymDBUSDSOMemoryPool, NULL); +	sSymDBUSDSOMemoryPool.create();  	if ( APR_SUCCESS == (rv = apr_dso_load(&sSymDBUSDSOHandle,  					       dbus_dso_name.c_str(), -					       sSymDBUSDSOMemoryPool) )) +					       sSymDBUSDSOMemoryPool()) ))  	{  		INFOMSG("Found DSO: %s", dbus_dso_name.c_str()); @@ -109,11 +109,7 @@ void ungrab_dbus_syms()  		sSymDBUSDSOHandleG = NULL;  	} -	if ( sSymDBUSDSOMemoryPool ) -	{ -		apr_pool_destroy(sSymDBUSDSOMemoryPool); -		sSymDBUSDSOMemoryPool = NULL; -	} +	sSymDBUSDSOMemoryPool.destroy();  	// NULL-out all of the symbols we'd grabbed  #define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{ll##DBUSSYM = NULL;}while(0) diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index c2916717bd..8929c0c1a4 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -113,6 +113,7 @@ int main( int argc, char **argv )  	}  	delete viewer_app_ptr;  	viewer_app_ptr = NULL; +  	return 0;  } diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index f781d5f3ff..fb9958ee9d 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -40,6 +40,7 @@  #include "llvertexbuffer.h"  #include "llviewerdisplay.h"  #include "llrender.h" +#include "pipeline.h"  // static  LLViewerDynamicTexture::instance_list_t LLViewerDynamicTexture::sInstances[ LLViewerDynamicTexture::ORDER_COUNT ]; @@ -201,7 +202,7 @@ void LLViewerDynamicTexture::postRender(BOOL success)  BOOL LLViewerDynamicTexture::updateAllInstances()  {  	sNumRenders = 0; -	if (gGLManager.mIsDisabled) +	if (gGLManager.mIsDisabled || LLPipeline::sMemAllocationThrottled)  	{  		return TRUE;  	} diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp index 1f334815d6..9f0218a95e 100644 --- a/indra/newview/llfloateranimpreview.cpp +++ b/indra/newview/llfloateranimpreview.cpp @@ -223,8 +223,7 @@ BOOL LLFloaterAnimPreview::postBuild()  		// now load bvh file  		S32 file_size; -		LLAPRFile infile ; -		infile.open(mFilenameAndPath, LL_APR_RB, NULL, &file_size); +		LLAPRFile infile(mFilenameAndPath, LL_APR_RB, &file_size);  		if (!infile.getFileHandle())  		{ diff --git a/indra/newview/llfloatermemleak.cpp b/indra/newview/llfloatermemleak.cpp index 58931d112e..9edfe1e354 100644 --- a/indra/newview/llfloatermemleak.cpp +++ b/indra/newview/llfloatermemleak.cpp @@ -90,6 +90,11 @@ LLFloaterMemLeak::~LLFloaterMemLeak()  void LLFloaterMemLeak::release()  { +	if(mLeakedMem.empty()) +	{ +		return ; +	} +  	for(S32 i = 0 ; i < (S32)mLeakedMem.size() ; i++)  	{  		delete[] mLeakedMem[i] ; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ef846ec42e..2510f43aa7 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -367,7 +367,7 @@ mCalculateBtn(NULL)  	mLastMouseX = 0;  	mLastMouseY = 0;  	mGLName = 0; -	mStatusLock = new LLMutex(NULL); +	mStatusLock = new LLMutex();  	mModelPreview = NULL;  	mLODMode[LLModel::LOD_HIGH] = 0; @@ -2878,7 +2878,7 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element)  //-----------------------------------------------------------------------------  LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) -: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) +: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex()  , mPelvisZOffset( 0.0f )  , mLegacyRigValid( false )  , mRigValidJointUpload( false ) diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index ec162e00eb..e4bd2049fa 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -181,6 +181,7 @@ LLFolderView::Params::Params()  // Default constructor  LLFolderView::LLFolderView(const Params& p)  :	LLFolderViewFolder(p), +	mRunningHeight(0),  	mScrollContainer( NULL ),  	mPopupMenuHandle(),  	mAllowMultiSelect(p.allow_multiselect), @@ -479,6 +480,7 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen  		target_height = running_height;  	} +	mRunningHeight = running_height;  	LLRect scroll_rect = mScrollContainer->getContentWindowRect();  	reshape( llmax(scroll_rect.getWidth(), total_width), running_height ); @@ -524,10 +526,11 @@ void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent)  	LLRect scroll_rect;  	if (mScrollContainer)  	{ +		LLView::reshape(width, height, called_from_parent);  		scroll_rect = mScrollContainer->getContentWindowRect();  	}  	width = llmax(mMinWidth, scroll_rect.getWidth()); -	height = llmax(height, scroll_rect.getHeight()); +	height = llmax(mRunningHeight, scroll_rect.getHeight());  	// restrict width with scroll container's width  	if (mUseEllipses) @@ -1915,9 +1918,9 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,  	if (!handled)  	{  		if (getListener()->getUUID().notNull()) -		{ -			LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); -		} +	{ +		LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); +	}  		else  		{  			if (!mFolders.empty()) diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 705a76a7b4..8af01e9102 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -314,6 +314,7 @@ protected:  	signal_t						mReshapeSignal;  	S32								mSignalSelectCallback;  	S32								mMinWidth; +	S32								mRunningHeight;  	std::map<LLUUID, LLFolderViewItem*> mItemMap;  	BOOL							mDragAndDropThisFrame; diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp index 5c020e6d98..d73048a28b 100644 --- a/indra/newview/llmainlooprepeater.cpp +++ b/indra/newview/llmainlooprepeater.cpp @@ -46,7 +46,7 @@ void LLMainLoopRepeater::start(void)  {  	if(mQueue != 0) return; -	mQueue = new LLThreadSafeQueue<LLSD>(gAPRPoolp, 1024); +	mQueue = new LLThreadSafeQueue<LLSD>(1024);  	mMainLoopConnection = LLEventPumps::instance().  		obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1));  	mRepeaterConnection = LLEventPumps::instance(). diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 1eb786f433..5bbef78dd4 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -319,6 +319,11 @@ BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )  	if (mContextMenu)  	{ +		// hide/show debugging options +		bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); +		mContextMenu->setItemVisible("open_webinspector", media_plugin_debugging_enabled ); +		mContextMenu->setItemVisible("debug_separator", media_plugin_debugging_enabled ); +  		mContextMenu->show(x, y);  		LLMenuGL::showPopup(this, mContextMenu, x, y);  	} @@ -385,12 +390,22 @@ void LLMediaCtrl::onFocusLost()  //  BOOL LLMediaCtrl::postBuild ()  { +	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; +	registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); +  	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(  		"menu_media_ctrl.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());  	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2)); +  	return TRUE;  } +void LLMediaCtrl::onOpenWebInspector() +{ +	if (mMediaSource && mMediaSource->hasMedia()) +		mMediaSource->getMediaPlugin()->showWebInspector( true ); +} +  ////////////////////////////////////////////////////////////////////////////////  //  BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask ) @@ -1065,6 +1080,12 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)  			mHoverTextChanged = true;  		};  		break; + +		case MEDIA_EVENT_DEBUG_MESSAGE: +		{ +			LL_INFOS("media") << self->getDebugMessageText() << LL_ENDL;  +		}; +		break;  	};  	// chain all events to any potential observers of this object. diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 0e4a5b1d65..3c0436e27a 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -166,6 +166,9 @@ public:  		// Incoming media event dispatcher  		virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); +		// right click debugging item +		void onOpenWebInspector(); +  		LLUUID getTextureID() {return mMediaTextureID;}  	protected: diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index afed306a28..fc594841e3 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -445,12 +445,12 @@ public:  };  LLMeshRepoThread::LLMeshRepoThread() -: LLThread("mesh repo", NULL)  +: LLThread("mesh repo")   {   	mWaiting = false; -	mMutex = new LLMutex(NULL); -	mHeaderMutex = new LLMutex(NULL); -	mSignal = new LLCondition(NULL); +	mMutex = new LLMutex(); +	mHeaderMutex = new LLMutex(); +	mSignal = new LLCondition();  }  LLMeshRepoThread::~LLMeshRepoThread() @@ -1199,7 +1199,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,  	mUploadTextures = upload_textures;  	mUploadSkin = upload_skin;  	mUploadJoints = upload_joints; -	mMutex = new LLMutex(NULL); +	mMutex = new LLMutex();  	mCurlRequest = NULL;  	mPendingUploads = 0;  	mFinished = false; @@ -2029,7 +2029,7 @@ LLMeshRepository::LLMeshRepository()  void LLMeshRepository::init()  { -	mMeshMutex = new LLMutex(NULL); +	mMeshMutex = new LLMutex();  	LLConvexDecomposition::getInstance()->initSystem(); @@ -2852,8 +2852,8 @@ LLPhysicsDecomp::LLPhysicsDecomp()  	mQuitting = false;  	mDone = false; -	mSignal = new LLCondition(NULL); -	mMutex = new LLMutex(NULL); +	mSignal = new LLCondition(); +	mMutex = new LLMutex();  }  LLPhysicsDecomp::~LLPhysicsDecomp() diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 1576ccccdf..bc594b5517 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -579,6 +579,11 @@ void LLPanelGroupGeneral::update(LLGroupChange gc)  	} +	// After role member data was changed in Roles->Members +	// need to update role titles. See STORM-918. +	if (gc == GC_ROLE_MEMBER_DATA) +		LLGroupMgr::getInstance()->sendGroupTitlesRequest(mGroupID); +  	// If this was just a titles update, we are done.  	if (gc == GC_TITLES) return; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index bef809f3a7..db7d836799 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -154,6 +154,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  	}  	updateLocationCombo(false); +	LLUICtrl& mode_combo = getChildRef<LLUICtrl>("mode_combo"); +	mode_combo.setValue(gSavedSettings.getString("SessionSettingsFile")); +	mode_combo.setCommitCallback(boost::bind(&LLPanelLogin::onModeChange, this, getChild<LLUICtrl>("mode_combo")->getValue(), _2)); +  	LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");  	server_choice_combo->setCommitCallback(onSelectServer, NULL);  	server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1)); @@ -1021,6 +1025,32 @@ void LLPanelLogin::updateLoginPanelLinks()  	sInstance->getChildView("forgot_password_text")->setVisible( system_grid);  } +void LLPanelLogin::onModeChange(const LLSD& original_value, const LLSD& new_value) +{ +	if (original_value.asString() != new_value.asString()) +	{ +		LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&LLPanelLogin::onModeChangeConfirm, this, original_value, new_value, _1, _2)); +	} +} + +void LLPanelLogin::onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response) +{ +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +	switch (option) +	{ +	case 0: +		gSavedSettings.getControl("SessionSettingsFile")->set(new_value); +		LLAppViewer::instance()->requestQuit(); +		break; +	case 1: +		// revert to original value +		getChild<LLUICtrl>("mode_combo")->setValue(original_value); +		break; +	default: +		break; +	} +} +  std::string canonicalize_username(const std::string& name)  {  	std::string cname = name; diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 4078eedc77..be9de884d1 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -87,6 +87,8 @@ private:  	void reshapeBrowser();  	void addFavoritesToStartLocation();  	void addUsersWithFavoritesToUsername(); +	void onModeChange(const LLSD& original_value, const LLSD& new_value); +	void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response);  	static void onClickConnect(void*);  	static void onClickNewAccount(void*);  	static void onClickVersion(void*); @@ -97,7 +99,6 @@ private:  	static void onServerComboLostFocus(LLFocusableElement*);  	static void updateServerCombo();  	static void updateStartSLURL(); -	  	static void updateLoginPanelLinks();  private: diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index 651897a217..a7c4057846 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -496,7 +496,7 @@ public:  		LLSideTray* side_tray = LLSideTray::getInstance();  		// Check if the tab we are dragging is docked. -		if (!side_tray->isTabAttached(getName())) return FALSE; +		if (!side_tray->isTabAttached(mTabName)) return FALSE;  		// Same value is hardcoded in LLDragHandle::handleHover().  		const S32 undock_threshold = 12; @@ -505,7 +505,7 @@ public:  		if (delta_x <= -undock_threshold ||	delta_x >= undock_threshold	||  			delta_y <= -undock_threshold ||	delta_y >= undock_threshold)  		{ -			LLSideTrayTab* tab = side_tray->getTab(getName()); +			LLSideTrayTab* tab = side_tray->getTab(mTabName);  			if (!tab) return FALSE;  			tab->setDocked(false); @@ -544,7 +544,12 @@ protected:  		, mDragLastScreenX(0)  		, mDragLastScreenY(0)  		, mBadgeDriver(NULL) -	{} +	{ +		// Find out the tab name to use in handleHover(). +		size_t pos = getName().find("_button"); +		llassert(pos != std::string::npos); +		mTabName = getName().substr(0, pos); +	}  	friend class LLUICtrlFactory; @@ -562,6 +567,7 @@ private:  	S32		mDragLastScreenX;  	S32		mDragLastScreenY; +	std::string					mTabName;  	LLSideTrayTabBadgeDriver*	mBadgeDriver;  }; @@ -679,6 +685,7 @@ LLSideTrayTab* LLSideTray::getTab(const std::string& name)  bool LLSideTray::isTabAttached(const std::string& name)  {  	LLSideTrayTab* tab = getTab(name); +	llassert(tab);  	if (!tab) return false;  	return std::find(mTabs.begin(), mTabs.end(), tab) != mTabs.end(); diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index 4cf1df1655..a853726dea 100644 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -273,11 +273,11 @@ LLSLURL::LLSLURL(const std::string& slurl)  			mRegion = LLURI::unescape(path_array[0].asString());  			path_array.erase(0); -			// parse the x, y, z -			if(path_array.size() >= 3) +			// parse the x, y, and optionally z +			if(path_array.size() >= 2)  			{	 -			  mPosition = LLVector3(path_array); +			  mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f)  			  if((F32(mPosition[VX]) < 0.f) ||                                (mPosition[VX] > REGION_WIDTH_METERS) ||  			     (F32(mPosition[VY]) < 0.f) ||  diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 1b8be7a5b2..0a00885843 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -162,6 +162,8 @@ BOOL LLStatusBar::handleRightMouseDown(S32 x, S32 y, MASK mask)  BOOL LLStatusBar::postBuild()  { +	LLControlVariablePtr mode_control = gSavedSettings.getControl("SessionSettingsFile"); +  	gMenuBarView->setRightMouseDownCallback(boost::bind(&show_navbar_context_menu, _1, _2, _3));  	mTextTime = getChild<LLTextBox>("TimeText" ); @@ -233,9 +235,40 @@ BOOL LLStatusBar::postBuild()  	mScriptOut = getChildView("scriptout"); +	LLUICtrl& mode_combo = getChildRef<LLUICtrl>("mode_combo"); +	mode_combo.setValue(gSavedSettings.getString("SessionSettingsFile")); +	mode_combo.setCommitCallback(boost::bind(&LLStatusBar::onModeChange, this, getChild<LLUICtrl>("mode_combo")->getValue(), _2)); + +  	return TRUE;  } +void LLStatusBar::onModeChange(const LLSD& original_value, const LLSD& new_value) +{ +	if (original_value.asString() != new_value.asString()) +	{ +		LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&LLStatusBar::onModeChangeConfirm, this, original_value, new_value, _1, _2)); +	} +} + +void LLStatusBar::onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response) +{ +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +	switch (option) +	{ +	case 0: +		gSavedSettings.getControl("SessionSettingsFile")->set(new_value); +		LLAppViewer::instance()->requestQuit(); +		break; +	case 1: +		// revert to original value +		getChild<LLUICtrl>("mode_combo")->setValue(original_value); +		break; +	default: +		break; +	} +} +  // Per-frame updates of visibility  void LLStatusBar::refresh()  { diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 4ea3183d18..e1e1f5459b 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -92,6 +92,8 @@ private:  	void onMouseEnterVolume();  	void onMouseEnterNearbyMedia();  	void onClickScreen(S32 x, S32 y); +	void onModeChange(const LLSD& original_value, const LLSD& new_value);
 +	void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response);
  	static void onClickMediaToggle(void* data);  	static void onClickBalance(void* data); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 9b417307fd..87b6304f9d 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -113,7 +113,7 @@ public:  	~LLTextureCacheWorker()  	{  		llassert_always(!haveWork()); -		delete[] mReadData; +		FREE_MEM(LLImageBase::getPrivatePool(), mReadData);  	}  	// override this interface @@ -176,7 +176,7 @@ private:  bool LLTextureCacheLocalFileWorker::doRead()  { -	S32 local_size = LLAPRFile::size(mFileName, mCache->getLocalAPRFilePool()); +	S32 local_size = LLAPRFile::size(mFileName);  	if (local_size > 0 && mFileName.size() > 4)  	{ @@ -215,7 +215,7 @@ bool LLTextureCacheLocalFileWorker::doRead()  			mDataSize = 0;  			return true;  		} -		mReadData = new U8[mDataSize]; +		mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize);  		mBytesRead = -1;  		mBytesToRead = mDataSize;  		setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); @@ -233,7 +233,7 @@ bool LLTextureCacheLocalFileWorker::doRead()  // 						<< " Bytes: " << mDataSize << " Offset: " << mOffset  // 						<< " / " << mDataSize << llendl;  				mDataSize = 0; // failed -				delete[] mReadData; +				FREE_MEM(LLImageBase::getPrivatePool(), mReadData);  				mReadData = NULL;  			}  			return true; @@ -248,9 +248,9 @@ bool LLTextureCacheLocalFileWorker::doRead()  	{  		mDataSize = local_size;  	} -	mReadData = new U8[mDataSize]; +	mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); -	S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool());	 +	S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize);  	if (bytes_read != mDataSize)  	{ @@ -258,7 +258,7 @@ bool LLTextureCacheLocalFileWorker::doRead()  // 				<< " Bytes: " << mDataSize << " Offset: " << mOffset  // 				<< " / " << mDataSize << llendl;  		mDataSize = 0; -		delete[] mReadData; +		FREE_MEM(LLImageBase::getPrivatePool(), mReadData);  		mReadData = NULL;  	}  	else @@ -331,7 +331,7 @@ bool LLTextureCacheRemoteWorker::doRead()  		// Is it a JPEG2000 file?   		{  			local_filename = filename + ".j2c"; -			local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); +			local_size = LLAPRFile::size(local_filename);  			if (local_size > 0)  			{  				mImageFormat = IMG_CODEC_J2C; @@ -341,7 +341,7 @@ bool LLTextureCacheRemoteWorker::doRead()  		if (local_size == 0)  		{  			local_filename = filename + ".jpg"; -			local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); +			local_size = LLAPRFile::size(local_filename);  			if (local_size > 0)  			{  				mImageFormat = IMG_CODEC_JPEG; @@ -352,7 +352,7 @@ bool LLTextureCacheRemoteWorker::doRead()  		if (local_size == 0)  		{  			local_filename = filename + ".tga"; -			local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); +			local_size = LLAPRFile::size(local_filename);  			if (local_size > 0)  			{  				mImageFormat = IMG_CODEC_TGA; @@ -377,16 +377,15 @@ bool LLTextureCacheRemoteWorker::doRead()  			mDataSize = local_size;  		}  		// Allocate read buffer -		mReadData = new U8[mDataSize]; -		S32 bytes_read = LLAPRFile::readEx(local_filename,  -											 mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool()); +		mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); +		S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize);  		if (bytes_read != mDataSize)  		{   			llwarns << "Error reading file from local cache: " << local_filename   					<< " Bytes: " << mDataSize << " Offset: " << mOffset   					<< " / " << mDataSize << llendl;  			mDataSize = 0; -			delete[] mReadData; +			FREE_MEM(LLImageBase::getPrivatePool(), mReadData);  			mReadData = NULL;  		}  		else @@ -429,15 +428,14 @@ bool LLTextureCacheRemoteWorker::doRead()  		S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;  		size = llmin(size, mDataSize);  		// Allocate the read buffer -		mReadData = new U8[size]; -		S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName,  -											 mReadData, offset, size, mCache->getLocalAPRFilePool()); +		mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), size); +		S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, mReadData, offset, size);  		if (bytes_read != size)  		{  			llwarns << "LLTextureCacheWorker: "  << mID  					<< " incorrect number of bytes read from header: " << bytes_read  					<< " / " << size << llendl; -			delete[] mReadData; +			FREE_MEM(LLImageBase::getPrivatePool(), mReadData);  			mReadData = NULL;  			mDataSize = -1; // failed  			done = true; @@ -457,7 +455,7 @@ bool LLTextureCacheRemoteWorker::doRead()  	if (!done && (mState == BODY))  	{  		std::string filename = mCache->getTextureFileName(mID); -		S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool()); +		S32 filesize = LLAPRFile::size(filename);  		if (filesize && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset)  		{ @@ -467,7 +465,7 @@ bool LLTextureCacheRemoteWorker::doRead()  			S32 data_offset, file_size, file_offset;  			// Reserve the whole data buffer first -			U8* data = new U8[mDataSize]; +			U8* data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize);  			// Set the data file pointers taking the read offset into account. 2 cases:  			if (mOffset < TEXTURE_CACHE_ENTRY_SIZE) @@ -480,7 +478,7 @@ bool LLTextureCacheRemoteWorker::doRead()  				// Copy the raw data we've been holding from the header cache into the new sized buffer  				llassert_always(mReadData);  				memcpy(data, mReadData, data_offset); -				delete[] mReadData; +				FREE_MEM(LLImageBase::getPrivatePool(), mReadData);  				mReadData = NULL;  			}  			else @@ -499,14 +497,13 @@ bool LLTextureCacheRemoteWorker::doRead()  			// Read the data at last  			S32 bytes_read = LLAPRFile::readEx(filename,   											 mReadData + data_offset, -											 file_offset, file_size, -											 mCache->getLocalAPRFilePool()); +											 file_offset, file_size);  			if (bytes_read != file_size)  			{  				llwarns << "LLTextureCacheWorker: "  << mID  						<< " incorrect number of bytes read from body: " << bytes_read  						<< " / " << file_size << llendl; -				delete[] mReadData; +				FREE_MEM(LLImageBase::getPrivatePool(), mReadData);  				mReadData = NULL;  				mDataSize = -1; // failed  				done = true; @@ -598,16 +595,16 @@ bool LLTextureCacheRemoteWorker::doWrite()  		{  			// We need to write a full record in the header cache so, if the amount of data is smaller  			// than a record, we need to transfer the data to a buffer padded with 0 and write that -			U8* padBuffer = new U8[TEXTURE_CACHE_ENTRY_SIZE]; +			U8* padBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), TEXTURE_CACHE_ENTRY_SIZE);  			memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE);		// Init with zeros  			memcpy(padBuffer, mWriteData, mDataSize);			// Copy the write buffer -			bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool()); -			delete [] padBuffer; +			bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size); +			FREE_MEM(LLImageBase::getPrivatePool(), padBuffer);  		}  		else  		{  			// Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file -			bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool()); +			bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size);  		}  		if (bytes_written <= 0) @@ -642,8 +639,7 @@ bool LLTextureCacheRemoteWorker::doWrite()  // 			llinfos << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << llendl;  			S32 bytes_written = LLAPRFile::writeEx(	filename,   													mWriteData + TEXTURE_CACHE_ENTRY_SIZE, -													0, file_size, -													mCache->getLocalAPRFilePool()); +													0, file_size);  			if (bytes_written <= 0)  			{  				llwarns << "LLTextureCacheWorker: "  << mID @@ -698,7 +694,7 @@ void LLTextureCacheWorker::finishWork(S32 param, bool completed)  			}  			else  			{ -				delete[] mReadData; +				FREE_MEM(LLImageBase::getPrivatePool(), mReadData);  				mReadData = NULL;  			}  		} @@ -740,9 +736,6 @@ void LLTextureCacheWorker::endWork(S32 param, bool aborted)  LLTextureCache::LLTextureCache(bool threaded)  	: LLWorkerThread("TextureCache", threaded), -	  mWorkersMutex(NULL), -	  mHeaderMutex(NULL), -	  mListMutex(NULL),  	  mHeaderAPRFile(NULL),  	  mReadOnly(TRUE), //do not allow to change the texture cache until setReadOnly() is called.  	  mTexturesSizeTotal(0), @@ -846,7 +839,7 @@ BOOL LLTextureCache::isInLocal(const LLUUID& id)  	// Is it a JPEG2000 file?   	{  		local_filename = filename + ".j2c"; -		local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); +		local_size = LLAPRFile::size(local_filename);  		if (local_size > 0)  		{  			return TRUE ; @@ -856,7 +849,7 @@ BOOL LLTextureCache::isInLocal(const LLUUID& id)  	// If not, is it a jpeg file?		  	{  		local_filename = filename + ".jpg"; -		local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); +		local_size = LLAPRFile::size(local_filename);  		if (local_size > 0)  		{  			return TRUE ; @@ -866,7 +859,7 @@ BOOL LLTextureCache::isInLocal(const LLUUID& id)  	// Hmm... What about a targa file? (used for UI texture mostly)		  	{  		local_filename = filename + ".tga"; -		local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); +		local_size = LLAPRFile::size(local_filename);  		if (local_size > 0)  		{  			return TRUE ; @@ -912,10 +905,10 @@ void LLTextureCache::purgeCache(ELLPath location)  		if(LLFile::isdir(mTexturesDirName))  		{  			std::string file_name = gDirUtilp->getExpandedFilename(location, entries_filename); -			LLAPRFile::remove(file_name, getLocalAPRFilePool()); +			LLAPRFile::remove(file_name);  			file_name = gDirUtilp->getExpandedFilename(location, cache_filename); -			LLAPRFile::remove(file_name, getLocalAPRFilePool()); +			LLAPRFile::remove(file_name);  			purgeAllTextures(true);  		} @@ -991,7 +984,9 @@ LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset)  {  	llassert_always(mHeaderAPRFile == NULL);  	apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY; -	mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, getLocalAPRFilePool()); +	// All code calling openHeaderEntriesFile, immediately calls closeHeaderEntriesFile, +	// so this file is very short-lived. +	mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags);  	if(offset > 0)  	{  		mHeaderAPRFile->seek(APR_SET, offset); @@ -1014,10 +1009,9 @@ void LLTextureCache::readEntriesHeader()  {  	// mHeaderEntriesInfo initializes to default values so safe not to read it  	llassert_always(mHeaderAPRFile == NULL); -	if (LLAPRFile::isExist(mHeaderEntriesFileName, getLocalAPRFilePool())) +	if (LLAPRFile::isExist(mHeaderEntriesFileName))  	{ -		LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo), -						  getLocalAPRFilePool()); +		LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));  	}  	else //create an empty entries header.  	{ @@ -1032,8 +1026,7 @@ void LLTextureCache::writeEntriesHeader()  	llassert_always(mHeaderAPRFile == NULL);  	if (!mReadOnly)  	{ -		LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo), -						   getLocalAPRFilePool()); +		LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));  	}  } @@ -1622,7 +1615,7 @@ void LLTextureCache::purgeTextures(bool validate)  			if (uuididx == validate_idx)  			{   				LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL; -				S32 bodysize = LLAPRFile::size(filename, getLocalAPRFilePool()); +				S32 bodysize = LLAPRFile::size(filename);  				if (bodysize != entries[idx].mBodySize)  				{  					LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize @@ -1857,7 +1850,7 @@ void LLTextureCache::removeCachedTexture(const LLUUID& id)  		mTexturesSizeMap.erase(id);  	}  	mHeaderIDMap.erase(id); -	LLAPRFile::remove(getTextureFileName(id), getLocalAPRFilePool());		 +	LLAPRFile::remove(getTextureFileName(id));		  }  //called after mHeaderMutex is locked. @@ -1869,7 +1862,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename)  	{  		if (entry.mBodySize == 0)	// Always attempt to remove when mBodySize > 0.  		{ -		  if (LLAPRFile::isExist(filename, getLocalAPRFilePool()))		// Sanity check. Shouldn't exist when body size is 0. +		  if (LLAPRFile::isExist(filename))		// Sanity check. Shouldn't exist when body size is 0.  		  {  			  LL_WARNS("TextureCache") << "Entry has body size of zero but file " << filename << " exists. Deleting this file, too." << LL_ENDL;  		  } @@ -1890,7 +1883,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename)  	if (file_maybe_exists)  	{ -		LLAPRFile::remove(filename, getLocalAPRFilePool());		 +		LLAPRFile::remove(filename);  	}  } diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 64e3a2658c..79f5ba5835 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -142,9 +142,6 @@ protected:  	std::string getTextureFileName(const LLUUID& id);  	void addCompleted(Responder* responder, bool success); -protected: -	//void setFileAPRPool(apr_pool_t* pool) { mFileAPRPool = pool ; } -  private:  	void setDirNames(ELLPath location);  	void readHeaderCache(); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 18c3a3b87d..e9be45ffd0 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -674,7 +674,6 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,  	  mRetryAttempt(0),  	  mActiveCount(0),  	  mGetStatus(0), -	  mWorkMutex(NULL),  	  mFirstPacket(0),  	  mLastPacket(-1),  	  mTotalPackets(0), @@ -817,7 +816,7 @@ void LLTextureFetchWorker::setImagePriority(F32 priority)  void LLTextureFetchWorker::resetFormattedData()  { -	delete[] mBuffer; +	FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);  	mBuffer = NULL;  	mBufferSize = 0;  	if (mFormattedImage.notNull()) @@ -888,7 +887,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  		mSentRequest = UNSENT;  		mDecoded  = FALSE;  		mWritten  = FALSE; -		delete[] mBuffer; +		FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);  		mBuffer = NULL;  		mBufferSize = 0;  		mHaveAllData = FALSE; @@ -1284,7 +1283,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  			llassert_always(mBufferSize == cur_size + mRequestedSize);  			if(!mBufferSize)//no data received.  			{ -				delete[] mBuffer;  +				FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);   				mBuffer = NULL;  				//abort. @@ -1312,7 +1311,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  				mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded.  			} -			U8* buffer = new U8[mBufferSize]; +			U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mBufferSize);  			if (cur_size > 0)  			{  				memcpy(buffer, mFormattedImage->getData(), cur_size); @@ -1321,7 +1320,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  			// NOTE: setData releases current data and owns new data (buffer)  			mFormattedImage->setData(buffer, mBufferSize);  			// delete temp data -			delete[] mBuffer; // Note: not 'buffer' (assigned in setData()) +			FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); // Note: not 'buffer' (assigned in setData())  			mBuffer = NULL;  			mBufferSize = 0;  			mLoadedDiscard = mRequestedDiscard; @@ -1618,7 +1617,7 @@ bool LLTextureFetchWorker::processSimulatorPackets()  			if (buffer_size > cur_size)  			{  				/// We have new data -				U8* buffer = new U8[buffer_size]; +				U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), buffer_size);  				S32 offset = 0;  				if (cur_size > 0 && mFirstPacket > 0)  				{ @@ -1670,7 +1669,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,  		if (data_size > 0)  		{  			// *TODO: set the formatted image data here directly to avoid the copy -			mBuffer = new U8[data_size]; +			mBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), data_size);  			buffer->readAfter(channels.in(), NULL, mBuffer, data_size);  			mBufferSize += data_size;  			if (data_size < mRequestedSize && mRequestedDiscard == 0) @@ -1816,8 +1815,6 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image  	  mDebugPause(FALSE),  	  mPacketCount(0),  	  mBadPacketCount(0), -	  mQueueMutex(getAPRPool()), -	  mNetworkQueueMutex(getAPRPool()),  	  mTextureCache(cache),  	  mImageDecodeThread(imagedecodethread),  	  mTextureBandwidth(0), diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index fa91f129b8..6873cf058a 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -307,8 +307,14 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vector<index_button_pair  	S32 bottom_offset = mIsScriptDialog ? (BTN_HEIGHT + IGNORE_BTN_TOP_DELTA + BOTTOM_PAD) : BOTTOM_PAD;  	S32 max_width = mControlPanel->getRect().getWidth();  	LLButton* ignore_btn = NULL; +	LLButton* mute_btn = NULL;  	for (std::vector<index_button_pair_t>::const_iterator it = buttons.begin(); it != buttons.end(); it++)  	{ +		if (-2 == it->first) +		{ +			mute_btn = it->second; +			continue; +		}  		if (it->first == -1)  		{  			ignore_btn = it->second; @@ -328,6 +334,8 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vector<index_button_pair  		left = btn_rect.mLeft + btn_rect.getWidth() + h_pad;  		mControlPanel->addChild(btn, -1);  	} + +	U32 ignore_btn_width = 0;  	if (mIsScriptDialog && ignore_btn != NULL)  	{  		LLRect ignore_btn_rect(ignore_btn->getRect()); @@ -340,8 +348,25 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vector<index_button_pair  		ignore_btn_rect.setOriginAndSize(ignore_btn_left, BOTTOM_PAD,// always move ignore button at the bottom  				ignore_btn_rect.getWidth(), ignore_btn_rect.getHeight());  		ignore_btn->setRect(ignore_btn_rect); +		ignore_btn_width = ignore_btn_rect.getWidth();  		mControlPanel->addChild(ignore_btn, -1);  	} + +	if (mIsScriptDialog && mute_btn != NULL) +	{ +		LLRect mute_btn_rect(mute_btn->getRect()); +		S32 buttons_per_row = max_width / BUTTON_WIDTH; //assume that h_pad far less than BUTTON_WIDTH +		// Place mute (Block) button to the left of the ignore button. +		S32 mute_btn_left = buttons_per_row * BUTTON_WIDTH + (buttons_per_row	- 1) * h_pad - mute_btn_rect.getWidth() - ignore_btn_width - (h_pad / 2); +		if (mute_btn_left + mute_btn_rect.getWidth() > max_width) // make sure that the mute button is in panel +		{ +			mute_btn_left = max_width - mute_btn_rect.getWidth() - 2 * HPAD; +		} +		mute_btn_rect.setOriginAndSize(mute_btn_left, BOTTOM_PAD,// always move mute button at the bottom +				mute_btn_rect.getWidth(), mute_btn_rect.getHeight()); +		mute_btn->setRect(mute_btn_rect); +		mControlPanel->addChild(mute_btn); +	}  }  void LLToastNotifyPanel::adjustPanelForScriptNotice(S32 button_panel_width, S32 button_panel_height) diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 39053fe9e4..6142ee0dd6 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -202,6 +202,7 @@ void display_stats()  		gMemoryAllocated = LLMemory::getCurrentRSS();  		U32 memory = (U32)(gMemoryAllocated / (1024*1024));  		llinfos << llformat("MEMORY: %d MB", memory) << llendl; +		LLMemory::logMemoryInfo() ;  		gRecentMemoryTime.reset();  	}  } @@ -692,7 +693,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)  				glh::matrix4f mod = glh_get_current_modelview();  				glViewport(0,0,512,512);  				LLVOAvatar::updateFreezeCounter() ; -				LLVOAvatar::updateImpostors(); + +				if(!LLPipeline::sMemAllocationThrottled) +				{		 +					LLVOAvatar::updateImpostors(); +				}  				glh_set_current_projection(proj);  				glh_set_current_modelview(mod); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 384f7cd61d..31b22119cb 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1776,6 +1776,7 @@ void LLViewerMediaImpl::createMediaSource()  			LL_WARNS("Media") << "Failed to initialize media for mime type " << mMimeType << LL_ENDL;  		}  	} +  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -1880,7 +1881,10 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_  			// collect 'javascript enabled' setting from prefs and send to embedded browser  			bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" );  			media_source->setJavascriptEnabled( javascript_enabled ); -			 +		 +			bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); +			media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled ); +  			media_source->setTarget(target);  			const std::string plugin_dir = gDirUtilp->getLLPluginDir(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index b29821479b..26599f557e 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -116,6 +116,8 @@  using namespace LLVOAvatarDefines; +typedef LLPointer<LLViewerObject> LLViewerObjectPtr; +  static boost::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels;  BOOL enable_land_build(void*); @@ -4010,23 +4012,21 @@ void handle_god_request_avatar_geometry(void *)  	}  } - -void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) +static bool get_derezzable_objects( +	EDeRezDestination dest, +	std::string& error, +	LLViewerRegion*& first_region, +	LLDynamicArray<LLViewerObjectPtr>* derez_objectsp, +	bool only_check = false)  { -	if(gAgentCamera.cameraMouselook()) -	{ -		gAgentCamera.changeCameraToDefault(); -	} -	//gInventoryView->setPanelOpen(TRUE); +	bool found = false; -	std::string error; -	LLDynamicArray<LLViewerObject*> derez_objects; +	LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();  	// Check conditions that we can't deal with, building a list of  	// everything that we'll actually be derezzing. -	LLViewerRegion* first_region = NULL; -	for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); -		 iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) +	for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); +		 iter != selection->valid_root_end(); iter++)  	{  		LLSelectNode* node = *iter;  		LLViewerObject* object = node->getObject(); @@ -4093,8 +4093,53 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)  		}  		if(can_derez_current)  		{ -			derez_objects.put(object); +			found = true; + +			if (only_check) +				// one found, no need to traverse to the end +				break; + +			if (derez_objectsp) +				derez_objectsp->put(object); + +		} +	} + +	return found; +} + +static bool can_derez(EDeRezDestination dest) +{ +	LLViewerRegion* first_region = NULL; +	std::string error; +	return get_derezzable_objects(dest, error, first_region, NULL, true); +} + +static void derez_objects( +	EDeRezDestination dest, +	const LLUUID& dest_id, +	LLViewerRegion*& first_region, +	std::string& error, +	LLDynamicArray<LLViewerObjectPtr>* objectsp) +{ +	LLDynamicArray<LLViewerObjectPtr> derez_objects; + +	if (!objectsp) // if objects to derez not specified +	{ +		// get them from selection +		if (!get_derezzable_objects(dest, error, first_region, &derez_objects, false)) +		{ +			llwarns << "No objects to derez" << llendl; +			return;  		} + +		objectsp = &derez_objects; +	} + + +	if(gAgentCamera.cameraMouselook()) +	{ +		gAgentCamera.changeCameraToDefault();  	}  	// This constant is based on (1200 - HEADER_SIZE) / 4 bytes per @@ -4104,13 +4149,13 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)  	// satisfy anybody.  	const S32 MAX_ROOTS_PER_PACKET = 250;  	const S32 MAX_PACKET_COUNT = 254; -	F32 packets = ceil((F32)derez_objects.count() / (F32)MAX_ROOTS_PER_PACKET); +	F32 packets = ceil((F32)objectsp->count() / (F32)MAX_ROOTS_PER_PACKET);  	if(packets > (F32)MAX_PACKET_COUNT)  	{  		error = "AcquireErrorTooManyObjects";  	} -	if(error.empty() && derez_objects.count() > 0) +	if(error.empty() && objectsp->count() > 0)  	{  		U8 d = (U8)dest;  		LLUUID tid; @@ -4135,11 +4180,11 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)  			msg->addU8Fast(_PREHASH_PacketCount, packet_count);  			msg->addU8Fast(_PREHASH_PacketNumber, packet_number);  			objects_in_packet = 0; -			while((object_index < derez_objects.count()) +			while((object_index < objectsp->count())  				  && (objects_in_packet++ < MAX_ROOTS_PER_PACKET))  			{ -				LLViewerObject* object = derez_objects.get(object_index++); +				LLViewerObject* object = objectsp->get(object_index++);  				msg->nextBlockFast(_PREHASH_ObjectData);  				msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());  				// VEFFECT: DerezObject @@ -4164,6 +4209,13 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)  	}  } +static void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) +{ +	LLViewerRegion* first_region = NULL; +	std::string error; +	derez_objects(dest, dest_id, first_region, error, NULL); +} +  void handle_take_copy()  {  	if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; @@ -4175,12 +4227,19 @@ void handle_take_copy()  // You can return an object to its owner if it is on your land.  class LLObjectReturn : public view_listener_t  { +public: +	LLObjectReturn() : mFirstRegion(NULL) {} + +private:  	bool handleEvent(const LLSD& userdata)  	{  		if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true;  		mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); +		// Save selected objects, so that we still know what to return after the confirmation dialog resets selection. +		get_derezzable_objects(DRD_RETURN_TO_OWNER, mError, mFirstRegion, &mReturnableObjects); +  		LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2));  		return true;  	} @@ -4191,16 +4250,23 @@ class LLObjectReturn : public view_listener_t  		if (0 == option)  		{  			// Ignore category ID for this derez destination. -			derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null); +			derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, mFirstRegion, mError, &mReturnableObjects);  		} +		mReturnableObjects.clear(); +		mError.clear(); +		mFirstRegion = NULL; +  		// drop reference to current selection  		mObjectSelection = NULL;  		return false;  	} -protected:  	LLObjectSelectionHandle mObjectSelection; + +	LLDynamicArray<LLViewerObjectPtr> mReturnableObjects; +	std::string mError; +	LLViewerRegion* mFirstRegion;  }; @@ -4225,29 +4291,7 @@ class LLObjectEnableReturn : public view_listener_t  		}  		else  		{ -			LLViewerRegion* region = gAgent.getRegion(); -			if (region) -			{ -				// Estate owners and managers can always return objects. -				if (region->canManageEstate()) -				{ -					new_value = true; -				} -				else -				{ -					struct f : public LLSelectedObjectFunctor -					{ -						virtual bool apply(LLViewerObject* obj) -						{ -							return  -								obj->permModify() || -								obj->isReturnable(); -						} -					} func; -					const bool firstonly = true; -					new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); -				} -			} +			new_value = can_derez(DRD_RETURN_TO_OWNER);  		}  #endif  		return new_value; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index b9293b3b31..8139f7deda 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -149,7 +149,7 @@ void LLFilePickerThread::run()  //static  void LLFilePickerThread::initClass()  { -	sMutex = new LLMutex(NULL); +	sMutex = new LLMutex();  }  //static @@ -816,8 +816,7 @@ LLUUID upload_new_resource(  		uuid = tid.makeAssetID(gAgent.getSecureSessionID());  		// copy this file into the vfs for upload  		S32 file_size; -		LLAPRFile infile ; -		infile.open(filename, LL_APR_RB, NULL, &file_size); +		LLAPRFile infile(filename, LL_APR_RB, &file_size);  		if (infile.getFileHandle())  		{  			LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 64aeb750c6..68745d5aeb 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -6516,8 +6516,24 @@ bool callback_script_dialog(const LLSD& notification, const LLSD& response)  		rtn_text = LLNotification::getSelectedOptionName(response);  	} -	// Didn't click "Ignore" -	if (button_idx != -1) +	// Button -2 = Mute +	// Button -1 = Ignore - no processing needed for this button +	// Buttons 0 and above = dialog choices + +	if (-2 == button_idx) +	{ +		std::string object_name = notification["payload"]["object_name"].asString(); +		LLUUID object_id = notification["payload"]["object_id"].asUUID(); +		LLMute mute(object_id, object_name, LLMute::OBJECT); +		if (LLMuteList::getInstance()->add(mute)) +		{ +			// This call opens the sidebar, displays the block list, and highlights the newly blocked +			// object in the list so the user can see that their block click has taken effect. +			LLPanelBlockedList::showPanelAndSelect(object_id); +		} +	} + +	if (0 <= button_idx)  	{  		LLMessageSystem* msg = gMessageSystem;  		msg->newMessage("ScriptDialogReply"); @@ -6560,12 +6576,12 @@ void process_script_dialog(LLMessageSystem* msg, void**)  	std::string message;   	std::string first_name;  	std::string last_name; -	std::string title; +	std::string object_name;  	S32 chat_channel;  	msg->getString("Data", "FirstName", first_name);  	msg->getString("Data", "LastName", last_name); -	msg->getString("Data", "ObjectName", title); +	msg->getString("Data", "ObjectName", object_name);  	msg->getString("Data", "Message", message);  	msg->getS32("Data", "ChatChannel", chat_channel); @@ -6576,6 +6592,7 @@ void process_script_dialog(LLMessageSystem* msg, void**)  	payload["sender"] = msg->getSender().getIPandPort();  	payload["object_id"] = object_id;  	payload["chat_channel"] = chat_channel; +	payload["object_name"] = object_name;  	// build up custom form  	S32 button_count = msg->getNumberOfBlocks("Buttons"); @@ -6594,7 +6611,7 @@ void process_script_dialog(LLMessageSystem* msg, void**)  	}  	LLSD args; -	args["TITLE"] = title; +	args["TITLE"] = object_name;  	args["MESSAGE"] = message;  	LLNotificationPtr notification;  	if (!first_name.empty()) diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index dfa35edef4..90fbc41daa 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -485,6 +485,12 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent  {  	switch(event)  	{ +		case MEDIA_EVENT_DEBUG_MESSAGE: +		{ +			// LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_DEBUG_MESSAGE " << LL_ENDL; +		}; +		break; +  		case MEDIA_EVENT_CONTENT_UPDATED:  		{  			// LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 70509f9a9f..280337be0f 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -3109,9 +3109,16 @@ void LLViewerLODTexture::processTextureStats()  	{  		mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel) ;  	} +	else if(LLPipeline::sMemAllocationThrottled)//release memory of large textures by decrease their resolutions. +	{ +		if(scaleDown()) +		{ +			mDesiredDiscardLevel = mCachedRawDiscardLevel ; +		} +	}  } -void LLViewerLODTexture::scaleDown() +bool LLViewerLODTexture::scaleDown()  {  	if(hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel())  	{		 @@ -3122,7 +3129,10 @@ void LLViewerLODTexture::scaleDown()  		{  			tester->setStablizingTime() ;  		} + +		return true ;  	} +	return false ;  }  //----------------------------------------------------------------------------------------------  //end of LLViewerLODTexture diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index de528927b4..a4a5ae0a5b 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -597,7 +597,7 @@ public:  private:  	void init(bool firstinit) ; -	void scaleDown() ;		 +	bool scaleDown() ;		  private:  	F32 mDiscardVirtualSize;		// Virtual size used to calculate desired discard	 diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 8d4f9b346f..5893259d96 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -662,6 +662,17 @@ public:  			addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3]));  			ypos += y_inc;  		} + +		if (gSavedSettings.getBOOL("DebugShowPrivateMem")) +		{ +			LLPrivateMemoryPoolManager::getInstance()->updateStatistics() ; +			addText(xpos, ypos, llformat("Total Reserved(KB): %d", LLPrivateMemoryPoolManager::getInstance()->mTotalReservedSize / 1024)); +			ypos += y_inc; + +			addText(xpos, ypos, llformat("Total Allocated(KB): %d", LLPrivateMemoryPoolManager::getInstance()->mTotalAllocatedSize / 1024)); +			ypos += y_inc; +		} +  		// only display these messages if we are actually rendering beacons at this moment  		if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons"))  		{ @@ -1630,6 +1641,7 @@ LLViewerWindow::LLViewerWindow(  	}  	LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable"));  	LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ; +	gGL.init() ;  	if (LLFeatureManager::getInstance()->isSafe()  		|| (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion()) @@ -2026,15 +2038,17 @@ void LLViewerWindow::shutdownGL()  	llinfos << "All textures and llimagegl images are destroyed!" << llendl ;  	llinfos << "Cleaning up select manager" << llendl; -	LLSelectMgr::getInstance()->cleanup(); - -	LLVertexBuffer::cleanupClass(); +	LLSelectMgr::getInstance()->cleanup();	  	llinfos << "Stopping GL during shutdown" << llendl;  	stopGL(FALSE);  	stop_glerror();  	gGL.shutdown(); + +	LLVertexBuffer::cleanupClass(); + +	llinfos << "LLVertexBuffer cleaned." << llendl ;  }  // shutdownViews() and shutdownGL() need to be called first @@ -4148,6 +4162,19 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei  	{  		return FALSE;  	} +	//check if there is enough memory for the snapshot image +	if(LLPipeline::sMemAllocationThrottled) +	{ +		return FALSE ; //snapshot taking is disabled due to memory restriction. +	} +	if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K +	{ +		if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3)) +		{ +			llwarns << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << llendl ; +			return FALSE ; //there is no enough memory for taking this snapshot. +		} +	}  	// PRE SNAPSHOT  	gDisplaySwapBuffers = FALSE; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 7946846222..7c6a815def 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -7506,8 +7506,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )  // static  void LLVOAvatar::dumpArchetypeXML( void* )  { -	LLAPRFile outfile; -	outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB ); +	LLAPRFile outfile(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER, "new archetype.xml"), LL_APR_WB);  	apr_file_t* file = outfile.getFileHandle() ;  	if (!file)  	{ diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 6d457434b5..baf01ec066 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -268,7 +268,6 @@ LLVOCache::LLVOCache():  	mCacheSize(1)  {  	mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled"); -	mLocalAPRFilePoolp = new LLVolatileAPRPool() ;  }  LLVOCache::~LLVOCache() @@ -278,7 +277,6 @@ LLVOCache::~LLVOCache()  		writeCacheHeader();  		clearCacheInMemory();  	} -	delete mLocalAPRFilePoolp;  }  void LLVOCache::setDirNames(ELLPath location) @@ -435,7 +433,7 @@ void LLVOCache::removeFromCache(HeaderEntryInfo* entry)  	std::string filename;  	getObjectCacheFilename(entry->mHandle, filename); -	LLAPRFile::remove(filename, mLocalAPRFilePoolp); +	LLAPRFile::remove(filename);  	entry->mTime = INVALID_TIME ;  	updateEntry(entry) ; //update the head file.  } @@ -452,9 +450,9 @@ void LLVOCache::readCacheHeader()  	clearCacheInMemory();	  	bool success = true ; -	if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp)) +	if (LLAPRFile::isExist(mHeaderFileName))  	{ -		LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);		 +		LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY);		  		//read the meta element  		success = check_read(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ; @@ -539,7 +537,7 @@ void LLVOCache::writeCacheHeader()  	bool success = true ;  	{ -		LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); +		LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY);  		//write the meta element  		success = check_write(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ; @@ -577,7 +575,7 @@ void LLVOCache::writeCacheHeader()  BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)  { -	LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); +	LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY);  	apr_file.seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;  	return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; @@ -603,7 +601,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca  	{  		std::string filename;  		getObjectCacheFilename(handle, filename); -		LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp); +		LLAPRFile apr_file(filename, APR_READ|APR_BINARY);  		LLUUID cache_id ;  		success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ; @@ -726,7 +724,7 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:  	{  		std::string filename;  		getObjectCacheFilename(handle, filename); -		LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); +		LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY);  		success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ; @@ -751,4 +749,3 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:  	return ;  } - diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 14e3b4c793..13651c6779 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -142,7 +142,6 @@ private:  	U32                  mNumEntries;  	std::string          mHeaderFileName ;  	std::string          mObjectCacheDirName; -	LLVolatileAPRPool*   mLocalAPRFilePoolp ; 	  	header_entry_queue_t mHeaderEntryQueue;  	handle_entry_map_t   mHandleEntryMap;	 diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 0db0010688..8b942fbc6a 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -942,7 +942,7 @@ void LLVivoxVoiceClient::stateMachine()  				if(!mSocket)  				{ -					mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);	 +					mSocket = LLSocket::create(LLSocket::STREAM_TCP);	  				}  				mConnected = mSocket->blockingConnect(mDaemonHost); diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index 4f582fc2db..64ca94b567 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -178,8 +178,8 @@ void LLWatchdog::init(killer_event_callback func)  	mKillerCallback = func;  	if(!mSuspectsAccessMutex && !mTimer)  	{ -		mSuspectsAccessMutex = new LLMutex(NULL); -		mTimer = new LLWatchdogTimerThread(); +		mSuspectsAccessMutex = new LLMutex; +		mTimer = new LLWatchdogTimerThread;  		mTimer->setSleepTime(WATCHDOG_SLEEP_TIME_USEC / 1000);  		mLastClockCount = LLTimer::getTotalTime(); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 4a6ec7fdbb..a7ae456f3c 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -127,6 +127,12 @@ void LLWorld::destroyClass()  		LLVOCache::getInstance()->destroyClass() ;  	}  	LLViewerPartSim::getInstance()->destroyClass(); + +	mDefaultWaterTexturep = NULL ; +	for (S32 i = 0; i < 8; i++) +	{ +		mEdgeWaterObjects[i] = NULL; +	}  } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 7a26404138..a50f66f282 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -103,6 +103,7 @@  #include "llmutelist.h"  #include "lltoolpie.h"  #include "llcurl.h" +#include "llnotifications.h"  void check_stack_depth(S32 stack_depth) @@ -317,6 +318,7 @@ BOOL	LLPipeline::sRenderFrameTest = FALSE;  BOOL	LLPipeline::sRenderAttachedLights = TRUE;  BOOL	LLPipeline::sRenderAttachedParticles = TRUE;  BOOL	LLPipeline::sRenderDeferred = FALSE; +BOOL    LLPipeline::sMemAllocationThrottled = FALSE;  S32		LLPipeline::sVisibleLightCount = 0;  F32		LLPipeline::sMinRenderSize = 0.f; @@ -561,6 +563,24 @@ void LLPipeline::destroyGL()  static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); +//static +void LLPipeline::throttleNewMemoryAllocation(BOOL disable) +{ +	if(sMemAllocationThrottled != disable) +	{ +		sMemAllocationThrottled = disable ; + +		if(sMemAllocationThrottled) +		{ +			//send out notification +			LLNotification::Params params("LowMemory"); +			LLNotifications::instance().add(params); + +			//release some memory. +		} +	} +} +  void LLPipeline::resizeScreenTexture()  {  	LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 28e6526acd..3f0640221e 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -362,6 +362,8 @@ public:  	static void updateRenderDeferred();  	static void refreshRenderDeferred(); +	static void throttleNewMemoryAllocation(BOOL disable); +  	void addDebugBlip(const LLVector3& position, const LLColor4& color);  private: @@ -517,8 +519,9 @@ public:  	static BOOL				sRenderAttachedLights;  	static BOOL				sRenderAttachedParticles;  	static BOOL				sRenderDeferred; +	static BOOL             sMemAllocationThrottled;  	static S32				sVisibleLightCount; -	static F32				sMinRenderSize; +	static F32				sMinRenderSize;	  	//screen texture  	U32 					mScreenWidth; diff --git a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml index c39c26f25f..960da4bd7a 100644 --- a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml +++ b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml @@ -28,4 +28,16 @@      <menu_item_call.on_enable       function="Edit.EnablePaste" />    </menu_item_call> +  <menu_item_separator +   layout="topleft" +   name="debug_separator" +   visible="false" /> +  <menu_item_call +   label="Open Web Inspector" +   layout="topleft" +   name="open_webinspector" +   visible="false"> +    <menu_item_call.on_click +     function="Open.WebInspector" /> +  </menu_item_call>  </context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index b08e3abb71..36ebe73753 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2133,6 +2133,16 @@                 function="ToggleControl"                 parameter="DebugShowMemory" />              </menu_item_check> +	     <menu_item_check +               label="Show Private Mem Info" +               name="Show Private Mem Info"> +              <menu_item_check.on_check +               function="CheckControl" +               parameter="DebugShowPrivateMem" /> +              <menu_item_check.on_click +               function="ToggleControl" +               parameter="DebugShowPrivateMem" /> +            </menu_item_check>              <menu_item_separator/> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 104bcaf7d0..99ab56d10a 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6261,6 +6261,10 @@ Grant this request?  [MESSAGE]      <form name="form">        <button +       index="-2" +       name="Mute" +       text="Block"/> +      <button         index="-1"         name="Ignore"         text="Ignore"/> @@ -6276,6 +6280,10 @@ Grant this request?  [MESSAGE]      <form name="form">        <button +       index="-2" +       name="Mute" +       text="Block"/> +      <button         index="-1"         name="Ignore"         text="Ignore"/> @@ -7139,6 +7147,20 @@ Click and drag anywhere on the world to rotate your view      <tag>funds</tag>    </notification> +   <notification +   icon="alertmodal.tga" +   name="LowMemory" +   type="alertmodal"> +    Your memory pool is low. Some functions of SL are disabled to avoid crash. Please close other applications. Restart SL if this persists. +  </notification> + +  <notification +     icon="alertmodal.tga" +     name="ForceQuitDueToLowMemory" +     type="alertmodal"> +    SL will quit in 30 seconds due to out of memory. +  </notification> +    <notification    name="PopupAttempt"    icon="Popup_Caution" diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 0bc1be666e..983f93cb03 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -117,16 +117,33 @@ label="Remember password"    name="connect_btn"    top="35"    width="90" /> -  <menu_button -  left_pad="5" -  top="35" -  width="80" +  <text +  follows="left|bottom" +  font="SansSerifSmall" +  height="15" +  left_pad="10" +  name="mode_selection_text" +  top="20" +  width="130"> +    Mode: +  </text> +  <combo_box +    follows="left|bottom"    height="23" -  label="Mode ▲" -  name="mode_menu"   +    max_chars="128"    tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." -  menu_filename="menu_mode_change.xml" -    /> +    top_pad="0" +    name="mode_combo" +    width="110"> +    <combo_box.item +      label="Basic" +      name="Basic" +      value="settings_minimal.xml" /> +    <combo_box.item +      label="Advanced" +      name="Advanced" +      value="" /> +  </combo_box>    <text    follows="left|bottom"    font="SansSerifSmall" diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml index 8a7bd53054..9749b6fdd4 100644 --- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml @@ -97,7 +97,7 @@  	     mouse_opaque="false"  	     name="location_combo"  	     top_delta="0" -	     width="266"> +	     width="226">           <combo_list           mouse_wheel_opaque="true"/>  	     <!-- *TODO: Delete.  Let the location_input use the correct art sizes. @@ -137,7 +137,7 @@  	     name="search_combo_box"  	     tool_tip="Search"  	     top_delta="0" -	     width="200" > +	     width="244" >           <combo_editor            label="Search [SECOND_LIFE]"            name="search_combo_editor"/> diff --git a/indra/newview/skins/default/xui/en/panel_region_terrain.xml b/indra/newview/skins/default/xui/en/panel_region_terrain.xml index bbb8b40594..5d060c0a0d 100644 --- a/indra/newview/skins/default/xui/en/panel_region_terrain.xml +++ b/indra/newview/skins/default/xui/en/panel_region_terrain.xml @@ -193,7 +193,7 @@      </text>      <text         follows="left|top" -       height="20" +       height="60"         layout="topleft"         left_delta="0"         name="height_text_lbl11" diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index 23ad0e9528..c780cf2696 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -35,7 +35,7 @@      </panel.string>    <panel      height="18" -    left="-315" +    left="-355"      width="95"      top="1"      follows="right|top"  @@ -77,19 +77,28 @@       top="0"       width="55" />    </panel> -  <menu_button -     follows="right|top"     -    image_color="0 0 0 0" -    hover_glow_amount="0" +  <combo_box +    follows="right|top"    +    drop_down_button.pad_left="10"       left_pad="5"      top="0" -    width="55" -    height="18" -    label="Mode ▼" +    width="120" +    height="20" +    pad_left="5" +    name="mode_combo"      tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." -    menu_filename="menu_mode_change.xml" -    /> +    > +    <combo_box.item +      label="Basic Mode" +      name="Basic" +      value="settings_minimal.xml" /> +    <combo_box.item +      label="Advanced Mode" +      name="Advanced" +      value="" /> +  </combo_box>      <text +      left_pad="5"       type="string"       font="SansSerifSmall"       text_readonly_color="TimeTextColor" @@ -98,10 +107,9 @@       height="16"       top="5"       layout="topleft" -     left_pad="5"       name="TimeText"       tool_tip="Current time (Pacific)" -     width="90"> +     width="75">          24:00 AM PST      </text>      <button diff --git a/indra/newview/skins/default/xui/en/widgets/combo_box.xml b/indra/newview/skins/default/xui/en/widgets/combo_box.xml index d1f68a9ef9..82d620d1e6 100644 --- a/indra/newview/skins/default/xui/en/widgets/combo_box.xml +++ b/indra/newview/skins/default/xui/en/widgets/combo_box.xml @@ -16,6 +16,9 @@                                font="SansSerifSmall"                                scale_image="true"                                pad_right="24" +                              halign="left" +                              tab_stop="true" +                              follows="all"                                image_unselected="DropDown_Off"                                image_selected="DropDown_On"                                image_pressed="DropDown_Press"  diff --git a/indra/newview/skins/minimal/xui/en/main_view.xml b/indra/newview/skins/minimal/xui/en/main_view.xml index ec2683880a..0ce6cbc984 100644 --- a/indra/newview/skins/minimal/xui/en/main_view.xml +++ b/indra/newview/skins/minimal/xui/en/main_view.xml @@ -187,9 +187,9 @@         name="status_bar_container"         tab_stop="false"         height="30" -       left="-120" +       left="-160"         top="0" -       width="120" +       width="160"         visible="false"/>    <panel follows="top|bottom"           height="500" diff --git a/indra/newview/skins/minimal/xui/en/panel_login.xml b/indra/newview/skins/minimal/xui/en/panel_login.xml index d89a0c6be1..40d2df78e1 100644 --- a/indra/newview/skins/minimal/xui/en/panel_login.xml +++ b/indra/newview/skins/minimal/xui/en/panel_login.xml @@ -118,16 +118,33 @@ label="Remember password"    name="connect_btn"    top="35"    width="90" /> -  <menu_button -left_pad="10" -top="35" -width="80" -height="23" -label="Mode ▲" -name="mode_menu" -tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." -menu_filename="menu_mode_change.xml" -    /> +  <text +  follows="left|bottom" +  font="SansSerifSmall" +  height="15" +  left_pad="10" +  name="mode_selection_text" +  top="20" +  width="130"> +    Mode: +  </text> +  <combo_box +  follows="left|bottom" +  height="23" +  max_chars="128" +  tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." +  top_pad="0" +  name="mode_combo" +  width="110"> +    <combo_box.item +      label="Basic" +      name="Basic" +      value="settings_minimal.xml" /> +    <combo_box.item +      label="Advanced" +      name="Advanced" +      value="" /> +  </combo_box>  </layout_panel>  <layout_panel  tab_stop="false" diff --git a/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml b/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml index e50911b8d2..73a8564274 100644 --- a/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml @@ -63,7 +63,7 @@ width="31" />       mouse_opaque="false"       name="location_combo"       top_delta="0" -     width="390"> +     width="325">      </location_input>      <icon follows="right"            height="20" diff --git a/indra/newview/skins/minimal/xui/en/panel_status_bar.xml b/indra/newview/skins/minimal/xui/en/panel_status_bar.xml index 42e6f30d48..fdd6b5d6ec 100644 --- a/indra/newview/skins/minimal/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/minimal/xui/en/panel_status_bar.xml @@ -12,7 +12,7 @@   name="status"   top="19"   tab_stop="false" - width="120"> + width="185">      <panel.string       name="packet_loss_tooltip">          Packet Loss @@ -33,18 +33,27 @@       name="buycurrencylabel">          L$ [AMT]      </panel.string> -  <menu_button -     follows="right|top"     -    image_color="0 0 0 0" -    hover_glow_amount="0" -    left="5" -    top="7" -    width="55"   -    height="18" -    label="Mode ▼" -    tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." -    menu_filename="menu_mode_change.xml" -    /> +  <combo_box +   follows="right|top" +   left_pad="5" +   drop_down_button.pad_left="10" +   left="0" +   top="5" +   pad_left="5" +   width="120" +   height="23" +   name="mode_combo" +   tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." +    > +    <combo_box.item +      label="Basic Mode" +      name="Basic" +      value="settings_minimal.xml" /> +    <combo_box.item +      label="Advanced Mode" +      name="Advanced" +      value="" /> +  </combo_box>       <button       follows="right|top"       height="16" @@ -53,7 +62,7 @@       image_pressed="Pause_Press"       image_pressed_selected="Play_Press"       is_toggle="true" -     left="65" +     left_pad="5"       top="7"       name="media_toggle_btn"       tool_tip="Start/Stop All Media (Music, Video, Web pages)" diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp index acc6e814bc..102294959a 100644 --- a/indra/newview/tests/llworldmap_test.cpp +++ b/indra/newview/tests/llworldmap_test.cpp @@ -27,7 +27,6 @@  // Dependencies  #include "linden_common.h" -#include "llapr.h"  #include "llsingleton.h"  #include "lltrans.h"  #include "lluistring.h" diff --git a/indra/test/lltemplatemessagebuilder_tut.cpp b/indra/test/lltemplatemessagebuilder_tut.cpp index 09beb53869..532f26ee60 100644 --- a/indra/test/lltemplatemessagebuilder_tut.cpp +++ b/indra/test/lltemplatemessagebuilder_tut.cpp @@ -29,7 +29,6 @@  #include "linden_common.h"  #include "lltut.h" -#include "llapr.h"  #include "llmessagetemplate.h"  #include "llquaternion.h"  #include "lltemplatemessagebuilder.h" @@ -53,7 +52,6 @@ namespace tut  			static bool init = false;  			if(! init)  			{ -				ll_init_apr();  				const F32 circuit_heartbeat_interval=5;  				const F32 circuit_timeout=100; diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp index d971b33475..9a6ccd4d68 100644 --- a/indra/test/message_tut.cpp +++ b/indra/test/message_tut.cpp @@ -29,7 +29,6 @@  #include "linden_common.h"  #include "lltut.h" -#include "llapr.h"  #include "llmessageconfig.h"  #include "llsdserialize.h"  #include "llversionserver.h" @@ -62,7 +61,6 @@ namespace tut  			static bool init = false;  			if(!init)  			{ -				ll_init_apr();  				//init_prehash_data();  				init = true;  			} diff --git a/indra/test/test.cpp b/indra/test/test.cpp index ffdb0cb976..45e8aef99a 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -37,8 +37,8 @@  #include "linden_common.h"  #include "llerrorcontrol.h"  #include "lltut.h" +#include "llaprpool.h" -#include "apr_pools.h"  #include "apr_getopt.h"  // the CTYPE_WORKAROUND is needed for linux dev stations that don't @@ -349,17 +349,12 @@ int main(int argc, char **argv)  	ctype_workaround();  #endif -	apr_initialize(); -	apr_pool_t* pool = NULL; -	if(APR_SUCCESS != apr_pool_create(&pool, NULL)) -	{ -		std::cerr << "Unable to initialize pool" << std::endl; -		return 1; -	} +	LLAPRPool pool; +	pool.create();  	apr_getopt_t* os = NULL; -	if(APR_SUCCESS != apr_getopt_init(&os, pool, argc, argv)) +	if(APR_SUCCESS != apr_getopt_init(&os, pool(), argc, argv))  	{ -		std::cerr << "Unable to  pool" << std::endl; +		std::cerr << "Unable to initialize the arguments for parsing by apr_getopt()." << std::endl;  		return 1;  	} @@ -477,8 +472,6 @@ int main(int argc, char **argv)  		s.close();  	} -	apr_terminate(); -  	int retval = (success ? 0 : 1);  	return retval; diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp index 884b00f0cc..d5ee09c5bc 100644 --- a/indra/test_apps/llplugintest/llmediaplugintest.cpp +++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp @@ -27,7 +27,6 @@  #include "linden_common.h"  #include "indra_constants.h" -#include "llapr.h"  #include "llerrorcontrol.h"  #include <math.h> @@ -186,9 +185,6 @@ LLMediaPluginTest::LLMediaPluginTest( int app_window, int window_width, int wind  		std::cout << "Unable to read bookmarks from file: " << bookmarks_filename << std::endl;  	}; -	// initialize linden lab APR module -	ll_init_apr(); -  	// Set up llerror logging  	{  		LLError::initForApplication("."); diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp index c7b70c2de8..24ba00ad8e 100644 --- a/indra/viewer_components/updater/llupdateinstaller.cpp +++ b/indra/viewer_components/updater/llupdateinstaller.cpp @@ -26,6 +26,7 @@  #include "linden_common.h"  #include <apr_file_io.h>  #include "llapr.h" +#include "llscopedvolatileaprpool.h"  #include "llprocesslauncher.h"  #include "llupdateinstaller.h"  #include "lldir.h"  @@ -45,7 +46,8 @@ namespace {  	{  		std::string scriptFile = gDirUtilp->getBaseFileName(path);  		std::string newPath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, scriptFile); -		apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, gAPRPoolp); +		LLScopedVolatileAPRPool pool; +		apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, pool);  		if(status != APR_SUCCESS) throw RelocateError();  		return newPath; diff --git a/scripts/templates/template-cpp.cpp b/scripts/templates/template-cpp.cpp new file mode 100644 index 0000000000..35d8441c87 --- /dev/null +++ b/scripts/templates/template-cpp.cpp @@ -0,0 +1,30 @@ +/**  +* @file #filename#.cpp +* @brief Implementation of #filename# +* @author #getpass.getuser()#@lindenlab.com +* +* $LicenseInfo:firstyear=#datetime.datetime.now().year#&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) #datetime.datetime.now().year#, 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$ +*/ + + +#'' if ( skip_h ) else '%cinclude "%s.h"' % (35,filename)# + diff --git a/scripts/templates/template-h.h b/scripts/templates/template-h.h new file mode 100644 index 0000000000..ce7b4ddc87 --- /dev/null +++ b/scripts/templates/template-h.h @@ -0,0 +1,31 @@ +/**  +* @file   #filename#.h +* @brief  Header file for #filename# +* @author #getpass.getuser()#@lindenlab.com +* +* $LicenseInfo:firstyear=#datetime.datetime.now().year#&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) #datetime.datetime.now().year#, 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$ +*/ +#'%c'%35#ifndef LL_#filename.upper().replace('-','_')#_H +#'%c'%35#define LL_#filename.upper().replace('-','_')#_H + + +#'%c'%35#endif // LL_#filename.upper().replace('-','_')#_H  | 
