diff options
41 files changed, 854 insertions, 158 deletions
| @@ -258,3 +258,5 @@ c6175c955a19e9b9353d242889ec1779b5762522 DRTVWR-105_3.2.5-release  c6175c955a19e9b9353d242889ec1779b5762522 3.2.5-release  3d75c836d178c7c7e788f256afe195f6cab764a2 DRTVWR-111_3.2.7-beta1  3d75c836d178c7c7e788f256afe195f6cab764a2 3.2.7-beta1 +89980333c99dbaf1787fe20784f1d8849e9b5d4f 3.2.8-start +37dd400ad721e2a89ee820ffc1e7e433c68f3ca2 3.2.9-start diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 4063cc730b..a6ad6b125c 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -337,11 +337,7 @@ LLMutex::~LLMutex()  void LLMutex::lock()  { -#if LL_DARWIN -	if (mLockingThread == LLThread::currentID()) -#else -	if (mLockingThread == sThreadID) -#endif +	if(isSelfLocked())  	{ //redundant lock  		mCount++;  		return; @@ -398,6 +394,15 @@ bool LLMutex::isLocked()  	}  } +bool LLMutex::isSelfLocked() +{ +#if LL_DARWIN +	return mLockingThread == LLThread::currentID(); +#else +	return mLockingThread == sThreadID; +#endif +} +  U32 LLMutex::lockingThread() const  {  	return mLockingThread; diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index f0e0de6173..b52e70ab2e 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -151,6 +151,7 @@ public:  	void lock();		// blocks  	void unlock();  	bool isLocked(); 	// non-blocking, but does do a lock/unlock so not free +	bool isSelfLocked(); //return true if locked in a same thread  	U32 lockingThread() const; //get ID of locking thread  protected: diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 99ab053b25..a869c74189 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -28,8 +28,8 @@  #define LL_LLVERSIONVIEWER_H  const S32 LL_VERSION_MAJOR = 3; -const S32 LL_VERSION_MINOR = 2; -const S32 LL_VERSION_PATCH = 8; +const S32 LL_VERSION_MINOR = 3; +const S32 LL_VERSION_PATCH = 0;  const S32 LL_VERSION_BUILD = 0;  const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index 0316797f00..250cace6e9 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -32,6 +32,9 @@  #include "llmath.h"  #include "llmemtype.h"  #include "llstl.h" +#include "llthread.h" + +#define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED llassert(!mMutexp || mMutexp->isSelfLocked());  /**    * LLSegment @@ -224,7 +227,8 @@ void LLHeapBuffer::allocate(S32 size)   * LLBufferArray   */  LLBufferArray::LLBufferArray() : -	mNextBaseChannel(0) +	mNextBaseChannel(0), +	mMutexp(NULL)  {  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  } @@ -233,6 +237,8 @@ LLBufferArray::~LLBufferArray()  {  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  	std::for_each(mBuffers.begin(), mBuffers.end(), DeletePointer()); + +	delete mMutexp;  }  // static @@ -243,14 +249,57 @@ LLChannelDescriptors LLBufferArray::makeChannelConsumer(  	return rv;  } +void LLBufferArray::lock() +{ +	if(mMutexp) +	{ +		mMutexp->lock() ; +	} +} + +void LLBufferArray::unlock() +{ +	if(mMutexp) +	{ +		mMutexp->unlock() ; +	} +} + +LLMutex* LLBufferArray::getMutex() +{ +	return mMutexp ; +} + +void LLBufferArray::setThreaded(bool threaded) +{ +	if(threaded) +	{ +		if(!mMutexp) +		{ +			mMutexp = new LLMutex(NULL); +		} +	} +	else +	{ +		if(mMutexp) +		{ +			delete mMutexp ; +			mMutexp = NULL ; +		} +	} +} +  LLChannelDescriptors LLBufferArray::nextChannel()  {  	LLChannelDescriptors rv(mNextBaseChannel++);  	return rv;  } +//mMutexp should be locked before calling this.  S32 LLBufferArray::capacity() const  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED +  	S32 total = 0;  	const_buffer_iterator_t iter = mBuffers.begin();  	const_buffer_iterator_t end = mBuffers.end(); @@ -263,6 +312,8 @@ S32 LLBufferArray::capacity() const  bool LLBufferArray::append(S32 channel, const U8* src, S32 len)  { +	LLMutexLock lock(mMutexp) ; +  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  	std::vector<LLSegment> segments;  	if(copyIntoBuffers(channel, src, len, segments)) @@ -273,8 +324,11 @@ bool LLBufferArray::append(S32 channel, const U8* src, S32 len)  	return false;  } +//mMutexp should be locked before calling this.  bool LLBufferArray::prepend(S32 channel, const U8* src, S32 len)  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED +  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  	std::vector<LLSegment> segments;  	if(copyIntoBuffers(channel, src, len, segments)) @@ -293,6 +347,8 @@ bool LLBufferArray::insertAfter(  {  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  	std::vector<LLSegment> segments; + +	LLMutexLock lock(mMutexp) ;  	if(mSegments.end() != segment)  	{  		++segment; @@ -305,8 +361,11 @@ bool LLBufferArray::insertAfter(  	return false;  } +//mMutexp should be locked before calling this.  LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address)  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED +  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  	segment_iterator_t end = mSegments.end();  	segment_iterator_t it = getSegment(address); @@ -335,20 +394,26 @@ LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address)  	return rv;  } +//mMutexp should be locked before calling this.  LLBufferArray::segment_iterator_t LLBufferArray::beginSegment()  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED  	return mSegments.begin();  } +//mMutexp should be locked before calling this.  LLBufferArray::segment_iterator_t LLBufferArray::endSegment()  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED  	return mSegments.end();  } +//mMutexp should be locked before calling this.  LLBufferArray::segment_iterator_t LLBufferArray::constructSegmentAfter(  	U8* address,  	LLSegment& segment)  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  	segment_iterator_t rv = mSegments.begin();  	segment_iterator_t end = mSegments.end(); @@ -395,8 +460,10 @@ LLBufferArray::segment_iterator_t LLBufferArray::constructSegmentAfter(  	return rv;  } +//mMutexp should be locked before calling this.  LLBufferArray::segment_iterator_t LLBufferArray::getSegment(U8* address)  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED  	segment_iterator_t end = mSegments.end();  	if(!address)  	{ @@ -414,9 +481,11 @@ LLBufferArray::segment_iterator_t LLBufferArray::getSegment(U8* address)  	return end;  } +//mMutexp should be locked before calling this.  LLBufferArray::const_segment_iterator_t LLBufferArray::getSegment(  	U8* address) const  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED  	const_segment_iterator_t end = mSegments.end();  	if(!address)  	{ @@ -466,6 +535,8 @@ S32 LLBufferArray::countAfter(S32 channel, U8* start) const  	S32 count = 0;  	S32 offset = 0;  	const_segment_iterator_t it; + +	LLMutexLock lock(mMutexp) ;  	const_segment_iterator_t end = mSegments.end();  	if(start)  	{ @@ -517,6 +588,8 @@ U8* LLBufferArray::readAfter(  	len = 0;  	S32 bytes_to_copy = 0;  	const_segment_iterator_t it; + +	LLMutexLock lock(mMutexp) ;  	const_segment_iterator_t end = mSegments.end();  	if(start)  	{ @@ -568,6 +641,7 @@ U8* LLBufferArray::seek(  	U8* start,  	S32 delta) const  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  	const_segment_iterator_t it;  	const_segment_iterator_t end = mSegments.end(); @@ -709,9 +783,14 @@ U8* LLBufferArray::seek(  	return rv;  } +//test use only  bool LLBufferArray::takeContents(LLBufferArray& source)  {  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER); + +	LLMutexLock lock(mMutexp); +	source.lock(); +  	std::copy(  		source.mBuffers.begin(),  		source.mBuffers.end(), @@ -723,13 +802,17 @@ bool LLBufferArray::takeContents(LLBufferArray& source)  		std::back_insert_iterator<segment_list_t>(mSegments));  	source.mSegments.clear();  	source.mNextBaseChannel = 0; +	source.unlock(); +  	return true;  } +//mMutexp should be locked before calling this.  LLBufferArray::segment_iterator_t LLBufferArray::makeSegment(  	S32 channel,  	S32 len)  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  	// start at the end of the buffers, because it is the most likely  	// to have free space. @@ -765,8 +848,10 @@ LLBufferArray::segment_iterator_t LLBufferArray::makeSegment(  	return send;  } +//mMutexp should be locked before calling this.  bool LLBufferArray::eraseSegment(const segment_iterator_t& erase_iter)  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  	// Find out which buffer contains the segment, and if it is found, @@ -792,13 +877,14 @@ bool LLBufferArray::eraseSegment(const segment_iterator_t& erase_iter)  	return rv;  } - +//mMutexp should be locked before calling this.  bool LLBufferArray::copyIntoBuffers(  	S32 channel,  	const U8* src,  	S32 len,  	std::vector<LLSegment>& segments)  { +	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED  	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);  	if(!src || !len) return false;  	S32 copied = 0; diff --git a/indra/llmessage/llbuffer.h b/indra/llmessage/llbuffer.h index 1c42b6fbc6..ccdb9fa7ee 100644 --- a/indra/llmessage/llbuffer.h +++ b/indra/llmessage/llbuffer.h @@ -39,6 +39,7 @@  #include <list>  #include <vector> +class LLMutex;  /**    * @class LLChannelDescriptors   * @brief A way simple interface to accesss channels inside a buffer @@ -564,6 +565,29 @@ public:  	 * @return Returns true on success.  	 */  	bool eraseSegment(const segment_iterator_t& iter); + +	/** +	* @brief Lock the mutex if it exists +	* This method locks mMutexp to make accessing LLBufferArray thread-safe +	*/ +	void lock(); + +	/** +	* @brief Unlock the mutex if it exists +	*/ +	void unlock(); + +	/** +	* @brief Return mMutexp +	*/ +	LLMutex* getMutex(); + +	/** +	* @brief Set LLBufferArray to be shared across threads or not +	* This method is to create mMutexp if is threaded. +	* @param threaded Indicates this LLBufferArray instance is shared across threads if true. +	*/ +	void setThreaded(bool threaded);  	//@}  protected: @@ -595,6 +619,7 @@ protected:  	S32 mNextBaseChannel;  	buffer_list_t mBuffers;  	segment_list_t mSegments; +	LLMutex* mMutexp;  };  #endif // LL_LLBUFFER_H diff --git a/indra/llmessage/llbufferstream.cpp b/indra/llmessage/llbufferstream.cpp index 6257983c43..8d8ad05ad5 100644 --- a/indra/llmessage/llbufferstream.cpp +++ b/indra/llmessage/llbufferstream.cpp @@ -31,6 +31,7 @@  #include "llbuffer.h"  #include "llmemtype.h" +#include "llthread.h"  static const S32 DEFAULT_OUTPUT_SEGMENT_SIZE = 1024 * 4; @@ -62,6 +63,7 @@ int LLBufferStreamBuf::underflow()  		return EOF;  	} +	LLMutexLock lock(mBuffer->getMutex());  	LLBufferArray::segment_iterator_t iter;  	LLBufferArray::segment_iterator_t end = mBuffer->endSegment();  	U8* last_pos = (U8*)gptr(); @@ -149,6 +151,7 @@ int LLBufferStreamBuf::overflow(int c)  	// since we got here, we have a buffer, and we have a character to  	// put on it.  	LLBufferArray::segment_iterator_t it; +	LLMutexLock lock(mBuffer->getMutex());  	it = mBuffer->makeSegment(mChannels.out(), DEFAULT_OUTPUT_SEGMENT_SIZE);  	if(it != mBuffer->endSegment())  	{ @@ -210,6 +213,7 @@ int LLBufferStreamBuf::sync()  	// *NOTE: I bet we could just --address if address is not NULL.  	// Need to think about that. +	LLMutexLock lock(mBuffer->getMutex());  	address = mBuffer->seek(mChannels.out(), address, -1);  	if(address)  	{ @@ -273,6 +277,8 @@ streampos LLBufferStreamBuf::seekoff(  			// NULL is fine  			break;  		} + +		LLMutexLock lock(mBuffer->getMutex());  		address = mBuffer->seek(mChannels.in(), base_addr, off);  		if(address)  		{ @@ -304,6 +310,8 @@ streampos LLBufferStreamBuf::seekoff(  			// NULL is fine  			break;  		} + +		LLMutexLock lock(mBuffer->getMutex());  		address = mBuffer->seek(mChannels.out(), base_addr, off);  		if(address)  		{ diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index e17380fdf5..3bcaffc275 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -72,10 +72,9 @@  static const U32 EASY_HANDLE_POOL_SIZE		= 5;  static const S32 MULTI_PERFORM_CALL_REPEAT	= 5; -static const S32 CURL_REQUEST_TIMEOUT = 30; // seconds +static const S32 CURL_REQUEST_TIMEOUT = 30; // seconds per operation  static const S32 MAX_ACTIVE_REQUEST_COUNT = 100; -static   // DEBUG //  S32 gCurlEasyCount = 0;  S32 gCurlMultiCount = 0; @@ -87,6 +86,11 @@ std::vector<LLMutex*> LLCurl::sSSLMutex;  std::string LLCurl::sCAPath;  std::string LLCurl::sCAFile;  LLCurlThread* LLCurl::sCurlThread = NULL ; +LLMutex* LLCurl::sHandleMutexp = NULL ; +S32      LLCurl::sTotalHandles = 0 ; +bool     LLCurl::sNotQuitting = true; +F32      LLCurl::sCurlRequestTimeOut = 120.f; //seonds +S32      LLCurl::sMaxHandles = 256; //max number of handles, (multi handles and easy handles combined).  void check_curl_code(CURLcode code)  { @@ -224,13 +228,15 @@ LLMutex* LLCurl::Easy::sHandleMutexp = NULL ;  //static  CURL* LLCurl::Easy::allocEasyHandle()  { +	llassert(LLCurl::getCurlThread()) ; +  	CURL* ret = NULL;  	LLMutexLock lock(sHandleMutexp) ;  	if (sFreeHandles.empty())  	{ -		ret = curl_easy_init(); +		ret = LLCurl::newEasyHandle();  	}  	else  	{ @@ -250,16 +256,27 @@ CURL* LLCurl::Easy::allocEasyHandle()  //static  void LLCurl::Easy::releaseEasyHandle(CURL* handle)  { +	static const S32 MAX_NUM_FREE_HANDLES = 32 ; +  	if (!handle)  	{ -		llerrs << "handle cannot be NULL!" << llendl; +		return ; //handle allocation failed. +		//llerrs << "handle cannot be NULL!" << llendl;  	}  	LLMutexLock lock(sHandleMutexp) ;  	if (sActiveHandles.find(handle) != sActiveHandles.end())  	{  		sActiveHandles.erase(handle); -		sFreeHandles.insert(handle); + +		if(sFreeHandles.size() < MAX_NUM_FREE_HANDLES) +		{ +			sFreeHandles.insert(handle); +		} +		else +		{ +			LLCurl::deleteEasyHandle(handle) ; +		}  	}  	else  	{ @@ -302,6 +319,14 @@ LLCurl::Easy::~Easy()  	--gCurlEasyCount;  	curl_slist_free_all(mHeaders);  	for_each(mStrings.begin(), mStrings.end(), DeletePointerArray()); + +	if (mResponder && LLCurl::sNotQuitting) //aborted +	{	 +		std::string reason("Request timeout, aborted.") ; +		mResponder->completedRaw(408, //HTTP_REQUEST_TIME_OUT, timeout, abort +			reason, mChannels, mOutput);		 +	} +	mResponder = NULL;  }  void LLCurl::Easy::resetState() @@ -474,6 +499,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,  	LLProxy::getInstance()->applyProxySettings(this);  	mOutput.reset(new LLBufferArray); +	mOutput->setThreaded(true);  	setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);  	setopt(CURLOPT_WRITEDATA, (void*)this); @@ -517,8 +543,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,  }  //////////////////////////////////////////////////////////////////////////// -LLMutex* LLCurl::Multi::sMultiInitMutexp = NULL ; -LLCurl::Multi::Multi() +LLCurl::Multi::Multi(F32 idle_time_out)  	: mQueued(0),  	  mErrorCount(0),  	  mState(STATE_READY), @@ -527,28 +552,47 @@ LLCurl::Multi::Multi()  	  mDeletionMutexp(NULL),  	  mEasyMutexp(NULL)  { -	mCurlMultiHandle = initMulti(); +	mCurlMultiHandle = LLCurl::newMultiHandle();  	if (!mCurlMultiHandle)  	{  		llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl; -		mCurlMultiHandle = initMulti(); +		mCurlMultiHandle = LLCurl::newMultiHandle();  	} -	llassert_always(mCurlMultiHandle);	 - -	if(LLCurl::getCurlThread()->getThreaded()) +	//llassert_always(mCurlMultiHandle);	 +	 +	if(mCurlMultiHandle)  	{ -		mMutexp = new LLMutex(NULL) ; -		mDeletionMutexp = new LLMutex(NULL) ; -		mEasyMutexp = new LLMutex(NULL) ; -	} -	LLCurl::getCurlThread()->addMulti(this) ; +		if(LLCurl::getCurlThread()->getThreaded()) +		{ +			mMutexp = new LLMutex(NULL) ; +			mDeletionMutexp = new LLMutex(NULL) ; +			mEasyMutexp = new LLMutex(NULL) ; +		} +		LLCurl::getCurlThread()->addMulti(this) ; -	++gCurlMultiCount; +		mIdleTimeOut = idle_time_out ; +		if(mIdleTimeOut < LLCurl::sCurlRequestTimeOut) +		{ +			mIdleTimeOut = LLCurl::sCurlRequestTimeOut ; +		} + +		++gCurlMultiCount; +	}  }  LLCurl::Multi::~Multi()  { +	cleanup() ;	 +} + +void LLCurl::Multi::cleanup() +{ +	if(!mCurlMultiHandle) +	{ +		return ; //nothing to clean. +	} +  	// Clean up active  	for(easy_active_list_t::iterator iter = mEasyActiveList.begin();  		iter != mEasyActiveList.end(); ++iter) @@ -564,7 +608,8 @@ LLCurl::Multi::~Multi()  	for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());	  	mEasyFreeList.clear(); -	check_curl_multi_code(curl_multi_cleanup(mCurlMultiHandle)); +	check_curl_multi_code(LLCurl::deleteMultiHandle(mCurlMultiHandle)); +	mCurlMultiHandle = NULL ;  	delete mMutexp ;  	mMutexp = NULL ; @@ -572,15 +617,13 @@ LLCurl::Multi::~Multi()  	mDeletionMutexp = NULL ;  	delete mEasyMutexp ;  	mEasyMutexp = NULL ; - +	 +	mQueued = 0 ; +	mState = STATE_COMPLETED; +	  	--gCurlMultiCount; -} - -CURLM* LLCurl::Multi::initMulti() -{ -	LLMutexLock lock(sMultiInitMutexp) ; -	return curl_multi_init() ; +	return ;  }  void LLCurl::Multi::lock() @@ -604,6 +647,7 @@ void LLCurl::Multi::markDead()  	LLMutexLock lock(mDeletionMutexp) ;  	mDead = TRUE ; +	LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_URGENT) ;   }  void LLCurl::Multi::setState(LLCurl::Multi::ePerformState state) @@ -630,6 +674,11 @@ bool LLCurl::Multi::isCompleted()  bool LLCurl::Multi::waitToComplete()  { +	if(!isValid()) +	{ +		return true ; +	} +  	if(!mMutexp) //not threaded  	{  		doPerform() ; @@ -639,7 +688,7 @@ bool LLCurl::Multi::waitToComplete()  	bool completed = (STATE_COMPLETED == mState) ;  	if(!completed)  	{ -		LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_URGENT) ; +		LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_HIGH) ;  	}  	return completed; @@ -689,7 +738,12 @@ bool LLCurl::Multi::doPerform()  		}  		mQueued = q;	 -		setState(STATE_COMPLETED) ; +		setState(STATE_COMPLETED) ;		 +		mIdleTimer.reset() ; +	} +	else if(mIdleTimer.getElapsedTimeF32() > mIdleTimeOut) //idle for too long, remove it. +	{ +		dead = true ;  	}  	return dead ; @@ -697,6 +751,11 @@ bool LLCurl::Multi::doPerform()  S32 LLCurl::Multi::process()  { +	if(!isValid()) +	{ +		return 0 ; +	} +  	waitToComplete() ;  	if (getState() != STATE_COMPLETED) @@ -849,7 +908,11 @@ bool LLCurlThread::CurlRequest::processRequest()  	if(mMulti)  	{  		completed = mCurlThread->doMultiPerform(mMulti) ; -		setPriority(LLQueuedThread::PRIORITY_LOW) ; + +		if(!completed) +		{ +			setPriority(LLQueuedThread::PRIORITY_LOW) ; +		}  	}  	return completed ; @@ -857,24 +920,26 @@ bool LLCurlThread::CurlRequest::processRequest()  void LLCurlThread::CurlRequest::finishRequest(bool completed)  { -	mCurlThread->deleteMulti(mMulti) ; +	if(mMulti->isDead()) +	{ +		mCurlThread->deleteMulti(mMulti) ; +	} +	else +	{ +		mCurlThread->cleanupMulti(mMulti) ; //being idle too long, remove the request. +	} +  	mMulti = NULL ;  }  LLCurlThread::LLCurlThread(bool threaded) :  	LLQueuedThread("curlthread", threaded)  { -	if(!LLCurl::Multi::sMultiInitMutexp) -	{ -		LLCurl::Multi::sMultiInitMutexp = new LLMutex(NULL) ; -	}  }  //virtual   LLCurlThread::~LLCurlThread()   { -	delete LLCurl::Multi::sMultiInitMutexp ; -	LLCurl::Multi::sMultiInitMutexp = NULL ;  }  S32 LLCurlThread::update(F32 max_time_ms) @@ -896,7 +961,19 @@ void LLCurlThread::addMulti(LLCurl::Multi* multi)  void LLCurlThread::killMulti(LLCurl::Multi* multi)  { -	multi->markDead() ; +	if(!multi) +	{ +		return ; +	} + +	if(multi->isValid()) +	{ +		multi->markDead() ; +	} +	else +	{ +		deleteMulti(multi) ; +	}  }  //private @@ -910,6 +987,13 @@ void LLCurlThread::deleteMulti(LLCurl::Multi* multi)  {  	delete multi ;  } + +//private +void LLCurlThread::cleanupMulti(LLCurl::Multi* multi)  +{ +	multi->cleanup() ; +} +  //------------------------------------------------------------  //static @@ -942,7 +1026,14 @@ LLCurlRequest::~LLCurlRequest()  void LLCurlRequest::addMulti()  {  	LLCurl::Multi* multi = new LLCurl::Multi(); -	 +	if(!multi->isValid()) +	{ +		LLCurl::getCurlThread()->killMulti(multi) ; +		mActiveMulti = NULL ; +		mActiveRequestCount = 0 ; +		return; +	} +  	mMultiSet.insert(multi);  	mActiveMulti = multi;  	mActiveRequestCount = 0; @@ -956,7 +1047,12 @@ LLCurl::Easy* LLCurlRequest::allocEasy()  	{  		addMulti();  	} -	llassert_always(mActiveMulti); +	if(!mActiveMulti) +	{ +		return NULL ; +	} + +	//llassert_always(mActiveMulti);  	++mActiveRequestCount;  	LLCurl::Easy* easy = mActiveMulti->allocEasy();  	return easy; @@ -1066,6 +1162,19 @@ S32 LLCurlRequest::process()  	{  		curlmulti_set_t::iterator curiter = iter++;  		LLCurl::Multi* multi = *curiter; + +		if(!multi->isValid()) +		{ +			if(multi == mActiveMulti) +			{				 +				mActiveMulti = NULL ; +				mActiveRequestCount = 0 ; +			} +			mMultiSet.erase(curiter) ; +			LLCurl::getCurlThread()->killMulti(multi) ; +			continue ; +		} +  		S32 tres = multi->process();  		res += tres;  		if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0) @@ -1086,6 +1195,19 @@ S32 LLCurlRequest::getQueued()  	{  		curlmulti_set_t::iterator curiter = iter++;  		LLCurl::Multi* multi = *curiter; +		 +		if(!multi->isValid()) +		{ +			if(multi == mActiveMulti) +			{				 +				mActiveMulti = NULL ; +				mActiveRequestCount = 0 ; +			} +			LLCurl::getCurlThread()->killMulti(multi); +			mMultiSet.erase(curiter) ; +			continue ; +		} +  		queued += multi->mQueued;  		if (multi->getState() != LLCurl::Multi::STATE_READY)  		{ @@ -1105,13 +1227,22 @@ LLCurlEasyRequest::LLCurlEasyRequest()  {  	mMulti = new LLCurl::Multi(); -	mEasy = mMulti->allocEasy(); -	if (mEasy) +	if(mMulti->isValid())  	{ -		mEasy->setErrorBuffer(); -		mEasy->setCA(); -		// Set proxy settings if configured to do so. -		LLProxy::getInstance()->applyProxySettings(mEasy); +		mEasy = mMulti->allocEasy(); +		if (mEasy) +		{ +			mEasy->setErrorBuffer(); +			mEasy->setCA(); +			// Set proxy settings if configured to do so. +			LLProxy::getInstance()->applyProxySettings(mEasy); +		} +	} +	else +	{ +		LLCurl::getCurlThread()->killMulti(mMulti) ; +		mEasy = NULL ; +		mMulti = NULL ;  	}  } @@ -1122,7 +1253,7 @@ LLCurlEasyRequest::~LLCurlEasyRequest()  void LLCurlEasyRequest::setopt(CURLoption option, S32 value)  { -	if (mEasy) +	if (isValid() && mEasy)  	{  		mEasy->setopt(option, value);  	} @@ -1130,7 +1261,7 @@ void LLCurlEasyRequest::setopt(CURLoption option, S32 value)  void LLCurlEasyRequest::setoptString(CURLoption option, const std::string& value)  { -	if (mEasy) +	if (isValid() && mEasy)  	{  		mEasy->setoptString(option, value);  	} @@ -1138,7 +1269,7 @@ void LLCurlEasyRequest::setoptString(CURLoption option, const std::string& value  void LLCurlEasyRequest::setPost(char* postdata, S32 size)  { -	if (mEasy) +	if (isValid() && mEasy)  	{  		mEasy->setopt(CURLOPT_POST, 1);  		mEasy->setopt(CURLOPT_POSTFIELDS, postdata); @@ -1148,7 +1279,7 @@ void LLCurlEasyRequest::setPost(char* postdata, S32 size)  void LLCurlEasyRequest::setHeaderCallback(curl_header_callback callback, void* userdata)  { -	if (mEasy) +	if (isValid() && mEasy)  	{  		mEasy->setopt(CURLOPT_HEADERFUNCTION, (void*)callback);  		mEasy->setopt(CURLOPT_HEADERDATA, userdata); // aka CURLOPT_WRITEHEADER @@ -1157,7 +1288,7 @@ void LLCurlEasyRequest::setHeaderCallback(curl_header_callback callback, void* u  void LLCurlEasyRequest::setWriteCallback(curl_write_callback callback, void* userdata)  { -	if (mEasy) +	if (isValid() && mEasy)  	{  		mEasy->setopt(CURLOPT_WRITEFUNCTION, (void*)callback);  		mEasy->setopt(CURLOPT_WRITEDATA, userdata); @@ -1166,7 +1297,7 @@ void LLCurlEasyRequest::setWriteCallback(curl_write_callback callback, void* use  void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userdata)  { -	if (mEasy) +	if (isValid() && mEasy)  	{  		mEasy->setopt(CURLOPT_READFUNCTION, (void*)callback);  		mEasy->setopt(CURLOPT_READDATA, userdata); @@ -1175,7 +1306,7 @@ void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userd  void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata)  { -	if (mEasy) +	if (isValid() && mEasy)  	{  		mEasy->setopt(CURLOPT_SSL_CTX_FUNCTION, (void*)callback);  		mEasy->setopt(CURLOPT_SSL_CTX_DATA, userdata); @@ -1184,7 +1315,7 @@ void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void*  void LLCurlEasyRequest::slist_append(const char* str)  { -	if (mEasy) +	if (isValid() && mEasy)  	{  		mEasy->slist_append(str);  	} @@ -1195,7 +1326,7 @@ void LLCurlEasyRequest::sendRequest(const std::string& url)  	llassert_always(!mRequestSent);  	mRequestSent = true;  	lldebugs << url << llendl; -	if (mEasy) +	if (isValid() && mEasy)  	{  		mEasy->setHeaders();  		mEasy->setoptString(CURLOPT_URL, url); @@ -1207,7 +1338,7 @@ void LLCurlEasyRequest::requestComplete()  {  	llassert_always(mRequestSent);  	mRequestSent = false; -	if (mEasy) +	if (isValid() && mEasy)  	{  		mMulti->removeEasy(mEasy);  	} @@ -1216,6 +1347,10 @@ void LLCurlEasyRequest::requestComplete()  // Usage: Call getRestult until it returns false (no more messages)  bool LLCurlEasyRequest::getResult(CURLcode* result, LLCurl::TransferInfo* info)  { +	if(!isValid()) +	{ +		return false ; +	}  	if (!mMulti->isCompleted())  	{ //we're busy, try again later  		return false; @@ -1280,7 +1415,7 @@ CURLMsg* LLCurlEasyRequest::info_read(S32* q, LLCurl::TransferInfo* info)  std::string LLCurlEasyRequest::getErrorString()  { -	return mEasy ? std::string(mEasy->getErrorBuffer()) : std::string(); +	return isValid() &&  mEasy ? std::string(mEasy->getErrorBuffer()) : std::string();  }  //////////////////////////////////////////////////////////////////////////// @@ -1306,8 +1441,11 @@ unsigned long LLCurl::ssl_thread_id(void)  }  #endif -void LLCurl::initClass(bool multi_threaded) +void LLCurl::initClass(F32 curl_reuest_timeout, S32 max_number_handles, bool multi_threaded)  { +	sCurlRequestTimeOut = curl_reuest_timeout ; //seconds +	sMaxHandles = max_number_handles ; //max number of handles, (multi handles and easy handles combined). +  	// Do not change this "unless you are familiar with and mean to control   	// internal operations of libcurl"  	// - http://curl.haxx.se/libcurl/c/curl_global_init.html @@ -1328,12 +1466,15 @@ void LLCurl::initClass(bool multi_threaded)  	sCurlThread = new LLCurlThread(multi_threaded) ;  	if(multi_threaded)  	{ +		sHandleMutexp = new LLMutex(NULL) ;  		Easy::sHandleMutexp = new LLMutex(NULL) ;  	}  }  void LLCurl::cleanupClass()  { +	sNotQuitting = false; //set quitting +  	//shut down curl thread  	while(1)  	{ @@ -1354,7 +1495,7 @@ void LLCurl::cleanupClass()  	for (std::set<CURL*>::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter)  	{  		CURL* curl = *iter; -		curl_easy_cleanup(curl); +		LLCurl::deleteEasyHandle(curl);  	}  	Easy::sFreeHandles.clear(); @@ -1362,9 +1503,77 @@ void LLCurl::cleanupClass()  	delete Easy::sHandleMutexp ;  	Easy::sHandleMutexp = NULL ; +	delete sHandleMutexp ; +	sHandleMutexp = NULL ; +  	llassert(Easy::sActiveHandles.empty());  } +//static  +CURLM* LLCurl::newMultiHandle() +{ +	LLMutexLock lock(sHandleMutexp) ; + +	if(sTotalHandles + 1 > sMaxHandles) +	{ +		llwarns << "no more handles available." << llendl ; +		return NULL ; //failed +	} +	sTotalHandles++; + +	CURLM* ret = curl_multi_init() ; +	if(!ret) +	{ +		llwarns << "curl_multi_init failed." << llendl ; +	} + +	return ret ; +} + +//static  +CURLMcode  LLCurl::deleteMultiHandle(CURLM* handle) +{ +	if(handle) +	{ +		LLMutexLock lock(sHandleMutexp) ;		 +		sTotalHandles-- ; +		return curl_multi_cleanup(handle) ; +	} +	return CURLM_OK ; +} + +//static  +CURL*  LLCurl::newEasyHandle() +{ +	LLMutexLock lock(sHandleMutexp) ; + +	if(sTotalHandles + 1 > sMaxHandles) +	{ +		llwarns << "no more handles available." << llendl ; +		return NULL ; //failed +	} +	sTotalHandles++; + +	CURL* ret = curl_easy_init() ; +	if(!ret) +	{ +		llwarns << "curl_easy_init failed." << llendl ; +	} + +	return ret ; +} + +//static  +void  LLCurl::deleteEasyHandle(CURL* handle) +{ +	if(handle) +	{ +		LLMutexLock lock(sHandleMutexp) ; +		curl_easy_cleanup(handle) ; +		sTotalHandles-- ; +	} +} +  const unsigned int LLCurl::MAX_REDIRECTS = 5;  // Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace. diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index 9c2c215c7a..fd664c0fa1 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -43,6 +43,7 @@  #include "llsd.h"  #include "llthread.h"  #include "llqueuedthread.h" +#include "llframetimer.h"  class LLMutex;  class LLCurlThread; @@ -162,7 +163,7 @@ public:  	/**  	 * @ brief Initialize LLCurl class  	 */ -	static void initClass(bool multi_threaded = false); +	static void initClass(F32 curl_reuest_timeout = 120.f, S32 max_number_handles = 256, bool multi_threaded = false);  	/**  	 * @ brief Cleanup LLCurl class @@ -182,11 +183,24 @@ public:  	static unsigned long ssl_thread_id(void);  	static LLCurlThread* getCurlThread() { return sCurlThread ;} + +	static CURLM* newMultiHandle() ; +	static CURLMcode deleteMultiHandle(CURLM* handle) ; +	static CURL*  newEasyHandle() ; +	static void   deleteEasyHandle(CURL* handle) ; +  private:  	static std::string sCAPath;  	static std::string sCAFile;  	static const unsigned int MAX_REDIRECTS;  	static LLCurlThread* sCurlThread; + +	static LLMutex* sHandleMutexp ; +	static S32      sTotalHandles ; +	static S32      sMaxHandles; +public: +	static bool     sNotQuitting; +	static F32      sCurlRequestTimeOut;	  };  class LLCurl::Easy @@ -277,7 +291,7 @@ public:  		STATE_COMPLETED=2  	} ePerformState; -	Multi();	 +	Multi(F32 idle_time_out = 0.f);	  	LLCurl::Easy* allocEasy();  	bool addEasy(LLCurl::Easy* easy);	 @@ -288,7 +302,10 @@ public:  	void setState(ePerformState state) ;  	ePerformState getState() ; +	  	bool isCompleted() ; +	bool isValid() {return mCurlMultiHandle != NULL ;} +	bool isDead() {return mDead;}  	bool waitToComplete() ; @@ -299,9 +316,9 @@ public:  	S32 mQueued;  	S32 mErrorCount; -	static CURLM* initMulti() ;  private:  	void easyFree(LLCurl::Easy*); +	void cleanup() ;  	CURLM* mCurlMultiHandle; @@ -319,8 +336,8 @@ private:  	LLMutex* mMutexp ;  	LLMutex* mDeletionMutexp ;  	LLMutex* mEasyMutexp ; - -	static LLMutex* sMultiInitMutexp ; +	LLFrameTimer mIdleTimer ; +	F32 mIdleTimeOut;  };  class LLCurlThread : public LLQueuedThread @@ -357,6 +374,7 @@ public:  private:  	bool doMultiPerform(LLCurl::Multi* multi) ;  	void deleteMulti(LLCurl::Multi* multi) ; +	void cleanupMulti(LLCurl::Multi* multi) ;  } ;  namespace boost @@ -414,6 +432,7 @@ public:  	std::string getErrorString();  	bool isCompleted() {return mMulti->isCompleted() ;}  	bool wait() { return mMulti->waitToComplete(); } +	bool isValid() {return mMulti && mMulti->isValid(); }  	LLCurl::Easy* getEasy() const { return mEasy; } diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp index 2bca517e97..612d765969 100644 --- a/indra/llmessage/llhttpassetstorage.cpp +++ b/indra/llmessage/llhttpassetstorage.cpp @@ -232,7 +232,8 @@ LLSD LLHTTPAssetRequest::getFullDetails() const  void LLHTTPAssetRequest::setupCurlHandle()  {  	// *NOTE: Similar code exists in mapserver/llcurlutil.cpp  JC -	mCurlHandle = curl_easy_init(); +	mCurlHandle = LLCurl::newEasyHandle(); +	llassert_always(mCurlHandle != NULL) ;  	// Apply proxy settings if configured to do so  	LLProxy::getInstance()->applyProxySettings(mCurlHandle); @@ -278,7 +279,7 @@ void LLHTTPAssetRequest::setupCurlHandle()  void LLHTTPAssetRequest::cleanupCurlHandle()  { -	curl_easy_cleanup(mCurlHandle); +	LLCurl::deleteEasyHandle(mCurlHandle);  	if (mAssetStoragep)  	{  		// Terminating a request.  Thus upload or download is no longer pending. @@ -429,12 +430,13 @@ void LLHTTPAssetStorage::_init(const std::string& web_host, const std::string& l  	// curl_global_init moved to LLCurl::initClass() -	mCurlMultiHandle = curl_multi_init(); +	mCurlMultiHandle = LLCurl::newMultiHandle() ; +	llassert_always(mCurlMultiHandle != NULL) ;  }  LLHTTPAssetStorage::~LLHTTPAssetStorage()  { -	curl_multi_cleanup(mCurlMultiHandle); +	LLCurl::deleteMultiHandle(mCurlMultiHandle);  	mCurlMultiHandle = NULL;  	// curl_global_cleanup moved to LLCurl::initClass() diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index dd4e3a6300..231cb7ca8f 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -228,6 +228,12 @@ static void request(  	LLPumpIO::chain_t chain;  	LLURLRequest* req = new LLURLRequest(method, url); +	if(!req->isValid())//failed +	{ +		delete req ; +		return ; +	} +  	req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); @@ -423,7 +429,9 @@ static LLSD blocking_request(  {  	lldebugs << "blockingRequest of " << url << llendl;  	char curl_error_buffer[CURL_ERROR_SIZE] = "\0"; -	CURL* curlp = curl_easy_init(); +	CURL* curlp = LLCurl::newEasyHandle(); +	llassert_always(curlp != NULL) ; +  	LLHTTPBuffer http_buffer;  	std::string body_str; @@ -517,7 +525,7 @@ static LLSD blocking_request(  	}  	// * Cleanup -	curl_easy_cleanup(curlp); +	LLCurl::deleteEasyHandle(curlp);  	return response;  } diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 73e8a69085..987f386aa3 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -818,6 +818,8 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(    			// Copy everything after mLast read to the out.  			LLBufferArray::segment_iterator_t seg_iter; + +			buffer->lock();  			seg_iter = buffer->splitAfter(mLastRead);  			if(seg_iter != buffer->endSegment())  			{ @@ -838,7 +840,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(  				}  #endif  			} - +			buffer->unlock();  			//  			// *FIX: get rid of extra bytes off the end  			// diff --git a/indra/llmessage/lliopipe.cpp b/indra/llmessage/lliopipe.cpp index 6e4eec74a6..8f827f7a30 100644 --- a/indra/llmessage/lliopipe.cpp +++ b/indra/llmessage/lliopipe.cpp @@ -75,6 +75,12 @@ LLIOPipe::~LLIOPipe()  	//lldebugs << "destroying LLIOPipe" << llendl;  } +//virtual  +bool LLIOPipe::isValid()  +{ +	return true ; +} +  // static  std::string LLIOPipe::lookupStatusString(EStatus status)  { diff --git a/indra/llmessage/lliopipe.h b/indra/llmessage/lliopipe.h index 8e656b6da1..cbd17b5a3d 100644 --- a/indra/llmessage/lliopipe.h +++ b/indra/llmessage/lliopipe.h @@ -231,6 +231,8 @@ public:  	 */  	virtual ~LLIOPipe(); +	virtual bool isValid() ; +  protected:  	/**  	 * @brief Base Constructor. diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index 54ceab3422..d5b4d45821 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -445,6 +445,7 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(  	// efficient - not only because writev() is better, but also  	// because we won't have to do as much work to find the start  	// address. +	buffer->lock();  	LLBufferArray::segment_iterator_t it;  	LLBufferArray::segment_iterator_t end = buffer->endSegment();  	LLSegment segment; @@ -524,6 +525,8 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(  		}  	} +	buffer->unlock(); +  	PUMP_DEBUG;  	if(done && eos)  	{ diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index a8d2a0a224..f3ef4f2684 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -195,7 +195,7 @@ bool LLPumpIO::prime(apr_pool_t* pool)  	return ((pool == NULL) ? false : true);  } -bool LLPumpIO::addChain(const chain_t& chain, F32 timeout) +bool LLPumpIO::addChain(const chain_t& chain, F32 timeout, bool has_curl_request)  {  	LLMemType m1(LLMemType::MTYPE_IO_PUMP);  	if(chain.empty()) return false; @@ -204,8 +204,10 @@ bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)  	LLScopedLock lock(mChainsMutex);  #endif  	LLChainInfo info; +	info.mHasCurlRequest = has_curl_request;  	info.setTimeoutSeconds(timeout);  	info.mData = LLIOPipe::buffer_ptr_t(new LLBufferArray); +	info.mData->setThreaded(has_curl_request);  	LLLinkInfo link;  #if LL_DEBUG_PIPE_TYPE_IN_PUMP  	lldebugs << "LLPumpIO::addChain() " << chain[0] << " '" @@ -440,6 +442,15 @@ void LLPumpIO::pump()  static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO"); +LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain)  +{ +	std::for_each( +				(*run_chain).mDescriptors.begin(), +				(*run_chain).mDescriptors.end(), +				ll_delete_apr_pollset_fd_client_data()); +	return mRunningChains.erase(run_chain); +} +  //timeout is in microseconds  void LLPumpIO::pump(const S32& poll_timeout)  { @@ -585,10 +596,16 @@ void LLPumpIO::pump(const S32& poll_timeout)  //						<< (*run_chain).mChainLinks[0].mPipe  //						<< " because we reached the end." << llendl;  #endif -				run_chain = mRunningChains.erase(run_chain); +				run_chain = removeRunningChain(run_chain);  				continue;  			}  		} +		else if(isChainExpired(*run_chain)) +		{ +			run_chain = removeRunningChain(run_chain); +			continue; +		} +  		PUMP_DEBUG;  		if((*run_chain).mLock)  		{ @@ -696,11 +713,7 @@ void LLPumpIO::pump(const S32& poll_timeout)  			PUMP_DEBUG;  			// This chain is done. Clean up any allocated memory and  			// erase the chain info. -			std::for_each( -				(*run_chain).mDescriptors.begin(), -				(*run_chain).mDescriptors.end(), -				ll_delete_apr_pollset_fd_client_data()); -			run_chain = mRunningChains.erase(run_chain); +			run_chain = removeRunningChain(run_chain);  			// *NOTE: may not always need to rebuild the pollset.  			mRebuildPollset = true; @@ -1095,6 +1108,24 @@ void LLPumpIO::processChain(LLChainInfo& chain)  	PUMP_DEBUG;  } +bool LLPumpIO::isChainExpired(LLChainInfo& chain) +{ +	if(!chain.mHasCurlRequest) +	{ +		return false ; +	} + +	for(links_t::iterator iter = chain.mChainLinks.begin(); iter != chain.mChainLinks.end(); ++iter) +	{ +		if(!(*iter).mPipe->isValid()) +		{ +			return true ; +		} +	} + +	return false ; +} +  bool LLPumpIO::handleChainError(  	LLChainInfo& chain,  	LLIOPipe::EStatus error) @@ -1136,6 +1167,9 @@ bool LLPumpIO::handleChainError(  #endif  			keep_going = false;  			break; +		case LLIOPipe::STATUS_EXPIRED: +			keep_going = false; +			break ;  		default:  			if(LLIOPipe::isSuccess(error))  			{ @@ -1157,7 +1191,8 @@ bool LLPumpIO::handleChainError(  LLPumpIO::LLChainInfo::LLChainInfo() :  	mInit(false),  	mLock(0), -	mEOS(false) +	mEOS(false), +	mHasCurlRequest(false)  {  	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..d2c5d37571 100644 --- a/indra/llmessage/llpumpio.h +++ b/indra/llmessage/llpumpio.h @@ -111,9 +111,10 @@ public:  	 * @param chain The pipes for the chain  	 * @param timeout The number of seconds in the future to  	 * expire. Pass in 0.0f to never expire. +	 * @param has_curl_request The chain contains LLURLRequest if true.  	 * @return Returns true if anything was added to the pump.  	 */ -	bool addChain(const chain_t& chain, F32 timeout); +	bool addChain(const chain_t& chain, F32 timeout, bool has_curl_request = false);  	/**   	 * @brief Struct to associate a pipe with it's buffer io indexes. @@ -356,12 +357,13 @@ protected:  		// basic member data  		bool mInit; +		bool mEOS; +		bool mHasCurlRequest;  		S32 mLock;  		LLFrameTimer mTimer;  		links_t::iterator mHead;  		links_t mChainLinks; -		LLIOPipe::buffer_ptr_t mData; -		bool mEOS; +		LLIOPipe::buffer_ptr_t mData;		  		LLSD mContext;  		// tracking inside the pump @@ -402,7 +404,7 @@ protected:  protected:  	void initialize(apr_pool_t* pool);  	void cleanup(); - +	current_chain_t removeRunningChain(current_chain_t& chain) ;  	/**   	 * @brief Given the internal state of the chains, rebuild the pollset  	 * @see setConditional() @@ -429,6 +431,9 @@ protected:  	 */  	bool handleChainError(LLChainInfo& chain, LLIOPipe::EStatus error); +	//if the chain is expired, remove it +	bool isChainExpired(LLChainInfo& chain) ; +  public:  	/**   	 * @brief Return number of running chains. diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h index 9fb49a5c33..0cecf4f688 100644 --- a/indra/llmessage/llsdrpcclient.h +++ b/indra/llmessage/llsdrpcclient.h @@ -240,9 +240,16 @@ public:  	virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const  	{  		lldebugs << "LLSDRPCClientFactory::build" << llendl; -		LLIOPipe::ptr_t service(new Client); -		chain.push_back(service);  		LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST)); +		if(!http->isValid()) +		{ +			llwarns << "Creating LLURLRequest failed." << llendl ; +			delete http; +			return false; +		} + +		LLIOPipe::ptr_t service(new Client); +		chain.push_back(service);		  		LLIOPipe::ptr_t http_pipe(http);  		http->addHeader("Content-Type: text/llsd");  		if(mURL.empty()) @@ -283,9 +290,16 @@ public:  	virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const  	{  		lldebugs << "LLXMLSDRPCClientFactory::build" << llendl; -		LLIOPipe::ptr_t service(new Client); -		chain.push_back(service); +  		LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST)); +		if(!http->isValid()) +		{ +			llwarns << "Creating LLURLRequest failed." << llendl ; +			delete http; +			return false ; +		} +		LLIOPipe::ptr_t service(new Client); +		chain.push_back(service);		  		LLIOPipe::ptr_t http_pipe(http);  		http->addHeader("Content-Type: text/xml");  		if(mURL.empty()) diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 261e57e79e..a16f5c7bf0 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -83,6 +83,12 @@ LLURLRequestDetail::LLURLRequestDetail() :  {  	LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);  	mCurlRequest = new LLCurlEasyRequest(); +	 +	if(!mCurlRequest->isValid()) //failed. +	{ +		delete mCurlRequest ; +		mCurlRequest = NULL ; +	}  }  LLURLRequestDetail::~LLURLRequestDetail() @@ -250,12 +256,24 @@ void LLURLRequest::allowCookies()  	mDetail->mCurlRequest->setoptString(CURLOPT_COOKIEFILE, "");  } +//virtual  +bool LLURLRequest::isValid()  +{ +	return mDetail->mCurlRequest && mDetail->mCurlRequest->isValid();  +} +  // virtual  LLIOPipe::EStatus LLURLRequest::handleError(  	LLIOPipe::EStatus status,  	LLPumpIO* pump)  {  	LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); +	 +	if(!isValid()) +	{ +		return STATUS_EXPIRED ; +	} +  	if(mCompletionCallback && pump)  	{  		LLURLRequestComplete* complete = NULL; @@ -441,6 +459,12 @@ void LLURLRequest::initialize()  	LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);  	mState = STATE_INITIALIZED;  	mDetail = new LLURLRequestDetail; + +	if(!isValid()) +	{ +		return ; +	} +  	mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);  	mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this);  	mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this); diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index ec5c2c1941..44d358d906 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -188,6 +188,8 @@ public:  	 */  	void allowCookies(); +	/*virtual*/ bool isValid() ; +  public:  	/**   	 * @brief Give this pipe a chance to handle a generated error diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index f26764cc42..b0ddacbb05 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -1434,6 +1434,8 @@ void LLRender::loadIdentity()  	flush();  	{ +		llassert_always(mMatrixMode < NUM_MATRIX_MODES) ; +  		mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity();  		mMatHash[mMatrixMode]++;  	} diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index a7151afeb1..230c1faa40 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -204,14 +204,26 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)  	Record rec;  	rec.mGLName = name;  	rec.mClientData = buffer; +<<<<<<< local +======= + +	sBytesPooled += size; +>>>>>>> other +<<<<<<< local  	if (buffer == NULL) +======= +	if (!LLVertexBuffer::sDisableVBOMapping && mUsage == GL_DYNAMIC_DRAW_ARB) +>>>>>>> other  	{  		glDeleteBuffersARB(1, &rec.mGLName);  	}  	else  	{ +<<<<<<< local  		sBytesPooled += size; +======= +>>>>>>> other  		mFreeList[i].push_back(rec);  	}  } @@ -547,7 +559,11 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of  void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const  {  	validateRange(start, end, count, indices_offset); +<<<<<<< local  	mMappable = false; +======= +	mMappable = FALSE; +>>>>>>> other  	gGL.syncMatrices();  	llassert(mNumVerts >= 0); @@ -602,7 +618,11 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi  void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const  {  	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); +<<<<<<< local  	mMappable = false; +======= +	mMappable = FALSE; +>>>>>>> other  	gGL.syncMatrices();  	llassert(mNumIndices >= 0); @@ -648,7 +668,11 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const  void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const  {  	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); +<<<<<<< local  	mMappable = false; +======= +	mMappable = FALSE; +>>>>>>> other  	gGL.syncMatrices();  	llassert(mNumVerts >= 0); @@ -822,6 +846,46 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :  		mMappable = false;  	} +<<<<<<< local +======= +	if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw) +	{ +		mUsage = 0; +	} +	 +	if (mUsage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw) +	{ +		mUsage = GL_STREAM_DRAW_ARB; +	} + +	if (mUsage == 0 && LLRender::sGLCoreProfile) +	{ //MUST use VBOs for all rendering +		mUsage = GL_STREAM_DRAW_ARB; +	} + +	if (mUsage && mUsage != GL_STREAM_DRAW_ARB) +	{ //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default +		if (sDisableVBOMapping) +		{ //always use stream draw if VBO mapping is disabled +			mUsage = GL_STREAM_DRAW_ARB; +		} +		else +		{ +			mUsage = GL_DYNAMIC_DRAW_ARB; +		} +	} +	 + +	if (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping) +	{ +		mMappable = TRUE; +	} +	else +	{ +		mMappable = FALSE; +	} + +>>>>>>> other  	//zero out offsets  	for (U32 i = 0; i < TYPE_MAX; i++)  	{ @@ -1072,7 +1136,11 @@ void LLVertexBuffer::destroyGLBuffer()  		}  		else  		{ +<<<<<<< local  			FREE_MEM(sPrivatePoolp, (void*) mMappedData); +======= +			FREE_MEM(sPrivatePoolp, (void*) mMappedData) ; +>>>>>>> other  			mMappedData = NULL;  			mEmpty = true;  		} @@ -1093,7 +1161,11 @@ void LLVertexBuffer::destroyGLIndices()  		}  		else  		{ +<<<<<<< local  			FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData); +======= +			FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData) ; +>>>>>>> other  			mMappedIndexData = NULL;  			mEmpty = true;  		} diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 0bf689bfad..036f535d81 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -260,7 +260,11 @@ public:  	volatile U8* getMappedIndices() const			{ return mMappedIndexData; }  	S32 getOffset(S32 type) const			{ return mOffsets[type]; }  	S32 getUsage() const					{ return mUsage; } +<<<<<<< local  	bool isWriteable() const				{ return (mMappable || mUsage == GL_STREAM_DRAW_ARB) ? true : false; } +======= +	BOOL isWriteable() const				{ return (mMappable || mUsage == GL_STREAM_DRAW_ARB) ? TRUE : FALSE; } +>>>>>>> other  	void draw(U32 mode, U32 count, U32 indices_offset) const;  	void drawArrays(U32 mode, U32 offset, U32 count) const; @@ -289,6 +293,7 @@ protected:  	volatile U8* mMappedData;	// pointer to currently mapped data (NULL if unmapped)  	volatile U8* mMappedIndexData;	// pointer to currently mapped indices (NULL if unmapped) +<<<<<<< local  	U32		mMappedDataUsingVBOs : 1;  	U32		mMappedIndexDataUsingVBOs : 1; @@ -298,6 +303,13 @@ protected:  	U32		mEmpty : 1;			// if true, client buffer is empty (or NULL). Old values have been discarded.	  	mutable bool	mMappable;     // if true, use memory mapping to upload data (otherwise doublebuffer and use glBufferSubData) +======= +	BOOL	mVertexLocked;			// if TRUE, vertex buffer is being or has been written to in client memory +	BOOL	mIndexLocked;			// if TRUE, index buffer is being or has been written to in client memory +	BOOL	mFinal;			// if TRUE, buffer can not be mapped again +	BOOL	mEmpty;			// if TRUE, client buffer is empty (or NULL). Old values have been discarded.	 +	mutable BOOL	mMappable;     // if TRUE, use memory mapping to upload data (otherwise doublebuffer and use glBufferSubData) +>>>>>>> other  	S32		mOffsets[TYPE_MAX];  	std::vector<MappedRegion> mMappedVertexRegions; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7df92e5276..0e26013152 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1828,6 +1828,28 @@        <key>Value</key>        <integer>0</integer>      </map> +  <key>CurlMaximumNumberOfHandles</key> +  <map> +    <key>Comment</key> +    <string>Maximum number of handles curl can use (requires restart)</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>S32</string> +    <key>Value</key> +    <integer>256</integer> +  </map> +  <key>CurlRequestTimeOut</key> +  <map> +    <key>Comment</key> +    <string>Max idle time of a curl request before killed (requires restart)</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>F32</string> +    <key>Value</key> +    <real>120.0</real> +  </map>    <key>CurlUseMultipleThreads</key>    <map>      <key>Comment</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 54ad3cd187..ab9b5ff436 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3314,6 +3314,7 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void *  	}  	llinfos << "Received cached texture response for " << num_results << " textures." << llendl; +	gAgentAvatarp->outputRezTiming("Fetched agent wearables textures from cache. Will now load them");  	gAgentAvatarp->updateMeshTextures(); diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 13b62cb019..09305a5b4d 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -185,6 +185,7 @@ void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)  {   	if (avatar)  	{ +		avatar->outputRezTiming("Sending wearables request");  		sendAgentWearablesRequest();  	}  } @@ -949,6 +950,11 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs  	if (mInitialWearablesUpdateReceived)  		return; +	if (isAgentAvatarValid()) +	{ +		gAgentAvatarp->outputRezTiming("Received initial wearables update"); +	} +  	// notify subscribers that wearables started loading. See EXT-7777  	// *TODO: find more proper place to not be called from deprecated method.  	// Seems such place is found: LLInitialWearablesFetch::processContents() @@ -1619,6 +1625,11 @@ void LLAgentWearables::queryWearableCache()  	//VWR-22113: gAgent.getRegion() can return null if invalid, seen here on logout  	if(gAgent.getRegion())  	{ +		if (isAgentAvatarValid()) +		{ +			gAgentAvatarp->outputRezTiming("Fetching textures from cache"); +		} +  		llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl;  		gMessageSystem->sendReliable(gAgent.getRegion()->getHost());  		gAgentQueryManager.mNumPendingQueries++; diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp index 4097ff707c..8cba54347e 100644 --- a/indra/newview/llagentwearablesfetch.cpp +++ b/indra/newview/llagentwearablesfetch.cpp @@ -87,6 +87,10 @@ public:  LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) :  	LLInventoryFetchDescendentsObserver(cof_id)  { +	if (isAgentAvatarValid()) +	{ +		gAgentAvatarp->outputRezTiming("Initial wearables fetch started"); +	}  }  LLInitialWearablesFetch::~LLInitialWearablesFetch() @@ -101,6 +105,10 @@ void LLInitialWearablesFetch::done()  	// idle tick instead.  	gInventory.removeObserver(this);  	doOnIdleOneTime(boost::bind(&LLInitialWearablesFetch::processContents,this)); +	if (isAgentAvatarValid()) +	{ +		gAgentAvatarp->outputRezTiming("Initial wearables fetch done"); +	}  }  void LLInitialWearablesFetch::add(InitialWearableData &data) diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h index 7dafab4a33..bedc445c0e 100644 --- a/indra/newview/llagentwearablesfetch.h +++ b/indra/newview/llagentwearablesfetch.h @@ -40,6 +40,8 @@  //--------------------------------------------------------------------  class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver  { +	LOG_CLASS(LLInitialWearablesFetch); +  public:  	LLInitialWearablesFetch(const LLUUID& cof_id);  	~LLInitialWearablesFetch(); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 663257042e..33f5373d7e 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -268,6 +268,8 @@ struct LLFoundData  class LLWearableHoldingPattern  { +	LOG_CLASS(LLWearableHoldingPattern); +  public:  	LLWearableHoldingPattern();  	~LLWearableHoldingPattern(); @@ -436,6 +438,11 @@ void LLWearableHoldingPattern::checkMissingWearables()  void LLWearableHoldingPattern::onAllComplete()  { +	if (isAgentAvatarValid()) +	{ +		gAgentAvatarp->outputRezTiming("Agent wearables fetch complete"); +	} +  	if (!isMostRecent())  	{  		llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; @@ -2363,6 +2370,8 @@ void LLAppearanceMgr::autopopulateOutfits()  // Handler for anything that's deferred until avatar de-clouds.  void LLAppearanceMgr::onFirstFullyVisible()  { +	gAgentAvatarp->outputRezTiming("Avatar fully loaded"); +	gAgentAvatarp->reportAvatarRezTime();  	gAgentAvatarp->debugAvatarVisible();  	// The auto-populate is failing at the point of generating outfits diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a455d359bf..49fbdbf1df 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -722,7 +722,9 @@ bool LLAppViewer::init()      // *NOTE:Mani - LLCurl::initClass is not thread safe.       // Called before threads are created. -    LLCurl::initClass(gSavedSettings.getBOOL("CurlUseMultipleThreads")); +    LLCurl::initClass(gSavedSettings.getF32("CurlRequestTimeOut"),  +						gSavedSettings.getS32("CurlMaximumNumberOfHandles"),  +						gSavedSettings.getBOOL("CurlUseMultipleThreads"));  	LL_INFOS("InitInfo") << "LLCurl initialized." << LL_ENDL ;      LLMachineID::init(); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index c0065a94e6..cebe93f042 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -73,7 +73,7 @@  #include "llwearablelist.h"  // Marketplace outbox current disabled -#define ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU	1 +#define ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU	0  #define ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU 0  #define BLOCK_WORN_ITEMS_IN_OUTBOX 1 diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index f2a24bf18a..bd20210190 100644..100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -514,9 +514,11 @@ void LLMeshRepoThread::run()  					mLODReqQ.pop();  					LLMeshRepository::sLODProcessing--;  					mMutex->unlock(); -					if (fetchMeshLOD(req.mMeshParams, req.mLOD)) +					if (!fetchMeshLOD(req.mMeshParams, req.mLOD, count))//failed, resubmit  					{ -						count++; +						mMutex->lock(); +						mLODReqQ.push(req) ;  +						mMutex->unlock();  					}  				}  			} @@ -528,9 +530,11 @@ void LLMeshRepoThread::run()  					HeaderRequest req = mHeaderReqQ.front();  					mHeaderReqQ.pop();  					mMutex->unlock(); -					if (fetchMeshHeader(req.mMeshParams)) +					if (!fetchMeshHeader(req.mMeshParams, count))//failed, resubmit  					{ -						count++; +						mMutex->lock(); +						mHeaderReqQ.push(req) ; +						mMutex->unlock();  					}  				}  			} @@ -675,6 +679,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  		return false;  	} +	bool ret = true ;  	U32 header_size = mMeshHeaderSize[mesh_id];  	if (header_size > 0) @@ -690,7 +695,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  			//check VFS for mesh skin info  			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);  			if (file.getSize() >= offset+size) -			{ +			{				  				LLMeshRepository::sCacheBytesRead += size;  				file.seek(offset);  				U8* buffer = new U8[size]; @@ -706,7 +711,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  				if (!zero)  				{ //attempt to parse  					if (skinInfoReceived(mesh_id, buffer, size)) -					{ +					{						  						delete[] buffer;  						return true;  					} @@ -721,10 +726,13 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  			std::string http_url = constructUrl(mesh_id);  			if (!http_url.empty()) -			{ -				LLMeshRepository::sHTTPRequestCount++; -				mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, -										   new LLMeshSkinInfoResponder(mesh_id, offset, size)); +			{				 +				ret = mCurlRequest->getByteRange(http_url, headers, offset, size, +												 new LLMeshSkinInfoResponder(mesh_id, offset, size)); +				if(ret) +				{ +					LLMeshRepository::sHTTPRequestCount++; +				}  			}  		}  	} @@ -734,7 +742,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  	}  	//early out was not hit, effectively fetched -	return true; +	return ret;  }  bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) @@ -748,7 +756,8 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  	}  	U32 header_size = mMeshHeaderSize[mesh_id]; - +	bool ret = true ; +	  	if (header_size > 0)  	{  		S32 version = mMeshHeader[mesh_id]["version"].asInteger(); @@ -764,6 +773,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  			if (file.getSize() >= offset+size)  			{  				LLMeshRepository::sCacheBytesRead += size; +  				file.seek(offset);  				U8* buffer = new U8[size];  				file.read(buffer, size); @@ -793,10 +803,13 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  			std::string http_url = constructUrl(mesh_id);  			if (!http_url.empty()) -			{ -				LLMeshRepository::sHTTPRequestCount++; -				mCurlRequest->getByteRange(http_url, headers, offset, size, -										   new LLMeshDecompositionResponder(mesh_id, offset, size)); +			{				 +				ret = mCurlRequest->getByteRange(http_url, headers, offset, size, +												 new LLMeshDecompositionResponder(mesh_id, offset, size)); +				if(ret) +				{ +					LLMeshRepository::sHTTPRequestCount++; +				}  			}  		}  	} @@ -806,7 +819,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  	}  	//early out was not hit, effectively fetched -	return true; +	return ret;  }  bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) @@ -820,6 +833,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)  	}  	U32 header_size = mMeshHeaderSize[mesh_id]; +	bool ret = true ;  	if (header_size > 0)  	{ @@ -865,10 +879,14 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)  			std::string http_url = constructUrl(mesh_id);  			if (!http_url.empty()) -			{ -				LLMeshRepository::sHTTPRequestCount++; -				mCurlRequest->getByteRange(http_url, headers, offset, size, -										   new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); +			{				 +				ret = mCurlRequest->getByteRange(http_url, headers, offset, size, +												 new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); + +				if(ret) +				{ +					LLMeshRepository::sHTTPRequestCount++; +				}  			}  		}  		else @@ -882,13 +900,12 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)  	}  	//early out was not hit, effectively fetched -	return true; +	return ret;  } -bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) +//return false if failed to get header +bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count)  { -	bool retval = false; -  	{  		//look for mesh in asset in vfs  		LLVFile file(gVFS, mesh_params.getSculptID(), LLAssetType::AT_MESH); @@ -903,35 +920,39 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)  			file.read(buffer, bytes);  			if (headerReceived(mesh_params, buffer, bytes))  			{ //did not do an HTTP request, return false -				return false; +				return true;  			}  		}  	} -	//either cache entry doesn't exist or is corrupt, request header from simulator - +	//either cache entry doesn't exist or is corrupt, request header from simulator	 +	bool retval = true ;  	std::vector<std::string> headers;  	headers.push_back("Accept: application/octet-stream");  	std::string http_url = constructUrl(mesh_params.getSculptID());  	if (!http_url.empty())  	{ -		retval = true;  		//grab first 4KB if we're going to bother with a fetch.  Cache will prevent future fetches if a full mesh fits  		//within the first 4KB -		//NOTE -- this will break of headers ever exceed 4KB -		LLMeshRepository::sHTTPRequestCount++; -		mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); +		//NOTE -- this will break of headers ever exceed 4KB		 +		retval = mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); +		if(retval) +		{ +			LLMeshRepository::sHTTPRequestCount++; +		} +		count++;  	}  	return retval;  } -bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) +//return false if failed to get mesh lod. +bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count)  { //protected by mMutex  	mHeaderMutex->lock(); -	bool retval = false; +	bool retval = true;  	LLUUID mesh_id = mesh_params.getSculptID(); @@ -968,7 +989,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  					if (lodReceived(mesh_params, lod, buffer, size))  					{  						delete[] buffer; -						return false; +						return true;  					}  				} @@ -981,11 +1002,15 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  			std::string http_url = constructUrl(mesh_id);  			if (!http_url.empty()) -			{ -				retval = true; -				LLMeshRepository::sHTTPRequestCount++; -				mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, +			{				 +				retval = mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size,  										   new LLMeshLODResponder(mesh_params, lod, offset, size)); + +				if(retval) +				{ +					LLMeshRepository::sHTTPRequestCount++; +				} +				count++;  			}  			else  			{ @@ -1555,8 +1580,17 @@ void LLMeshUploadThread::doWholeModelUpload()  		LLSD body = full_model_data["asset_resources"];  		dump_llsd_to_file(body,make_dump_name("whole_model_body_",dump_num));  		LLCurlRequest::headers_t headers; -		mCurlRequest->post(mWholeModelUploadURL, headers, body, -						   new LLWholeModelUploadResponder(this, full_model_data, mUploadObserverHandle), mMeshUploadTimeOut); + +		{ +			LLCurl::ResponderPtr responder = new LLWholeModelUploadResponder(this, full_model_data, mUploadObserverHandle) ; + +			while(!mCurlRequest->post(mWholeModelUploadURL, headers, body, responder, mMeshUploadTimeOut)) +			{ +				//sleep for 10ms to prevent eating a whole core +				apr_sleep(10000); +			} +		} +  		do  		{  			mCurlRequest->process(); @@ -1586,8 +1620,15 @@ void LLMeshUploadThread::requestWholeModelFee()  	mPendingUploads++;  	LLCurlRequest::headers_t headers; -	mCurlRequest->post(mWholeModelFeeCapability, headers, model_data, -					   new LLWholeModelFeeResponder(this,model_data, mFeeObserverHandle), mMeshUploadTimeOut); + +	{ +		LLCurl::ResponderPtr responder = new LLWholeModelFeeResponder(this,model_data, mFeeObserverHandle) ; +		while(!mCurlRequest->post(mWholeModelFeeCapability, headers, model_data, responder, mMeshUploadTimeOut)) +		{ +			//sleep for 10ms to prevent eating a whole core +			apr_sleep(10000); +		} +	}  	do  	{ diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 1bdbc2856b..da81bb057b 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -323,8 +323,8 @@ public:  	virtual void run();  	void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod); -	bool fetchMeshHeader(const LLVolumeParams& mesh_params); -	bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod); +	bool fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count); +	bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count);  	bool headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size);  	bool lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size);  	bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size); diff --git a/indra/newview/lltexlayer.h b/indra/newview/lltexlayer.h index 85dadb213c..4f43547dae 100644 --- a/indra/newview/lltexlayer.h +++ b/indra/newview/lltexlayer.h @@ -261,6 +261,8 @@ private:  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  class LLTexLayerSetBuffer : public LLViewerDynamicTexture  { +	LOG_CLASS(LLTexLayerSetBuffer); +  public:  	LLTexLayerSetBuffer(LLTexLayerSet* const owner, S32 width, S32 height);  	virtual ~LLTexLayerSetBuffer(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 5f64dba100..8a713ae22c 100644..100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1960,33 +1960,42 @@ void LLViewerWindow::shutdownViews()  	// clean up warning logger  	LLError::removeRecorder(RecordToChatConsole::getInstance()); +	llinfos << "Warning logger is cleaned." << llendl ; +  	delete mDebugText;  	mDebugText = NULL; +	llinfos << "DebugText deleted." << llendl ; +  	// Cleanup global views  	if (gMorphView)  	{  		gMorphView->setVisible(FALSE);  	} +	llinfos << "Global views cleaned." << llendl ;  	// DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open  	// will crump with LL_ERRS.  	LLModalDialog::shutdownModals(); -	 +	llinfos << "LLModalDialog shut down." << llendl;  +  	// destroy the nav bar, not currently part of gViewerWindow  	// *TODO: Make LLNavigationBar part of gViewerWindow  	if (LLNavigationBar::instanceExists())  	{  		delete LLNavigationBar::getInstance();  	} +	llinfos << "LLNavigationBar destroyed." << llendl ;  	// destroy menus after instantiating navbar above, as it needs  	// access to gMenuHolder  	cleanup_menus(); +	llinfos << "menus destroyed." << llendl ;  	// Delete all child views.  	delete mRootView;  	mRootView = NULL; +	llinfos << "RootView deleted." << llendl ;  	// Automatically deleted as children of mRootView.  Fix the globals.  	gStatusBar = NULL; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 4cd61cecf9..dd0317f555 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -78,6 +78,8 @@ class LLVOAvatar :  	public LLCharacter,  	public boost::signals2::trackable  { +	LOG_CLASS(LLVOAvatar); +  public:  	friend class LLVOAvatarSelf;  protected: diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 581912f844..f1df67494f 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1574,7 +1574,7 @@ void LLVOAvatarSelf::invalidateAll()  	{  		invalidateComposite(mBakedTextureDatas[i].mTexLayerSet, TRUE);  	} -	mDebugSelfLoadTimer.reset(); +	//mDebugSelfLoadTimer.reset();  }  //----------------------------------------------------------------------------- @@ -1896,11 +1896,13 @@ BOOL LLVOAvatarSelf::getIsCloud()  		gAgentWearables.getWearableCount(LLWearableType::WT_EYES) == 0 ||  		gAgentWearables.getWearableCount(LLWearableType::WT_SKIN) == 0)	  	{ +		lldebugs << "No body parts" << llendl;  		return TRUE;  	}  	if (!isTextureDefined(TEX_HAIR, 0))  	{ +		lldebugs << "No hair texture" << llendl;  		return TRUE;  	} @@ -1909,12 +1911,14 @@ BOOL LLVOAvatarSelf::getIsCloud()  		if (!isLocalTextureDataAvailable(mBakedTextureDatas[BAKED_LOWER].mTexLayerSet) &&  			(!isTextureDefined(TEX_LOWER_BAKED, 0)))  		{ +			lldebugs << "Lower textures not baked" << llendl;  			return TRUE;  		}  		if (!isLocalTextureDataAvailable(mBakedTextureDatas[BAKED_UPPER].mTexLayerSet) &&  			(!isTextureDefined(TEX_UPPER_BAKED, 0)))  		{ +			lldebugs << "Upper textures not baked" << llendl;  			return TRUE;  		} @@ -1931,10 +1935,12 @@ BOOL LLVOAvatarSelf::getIsCloud()  			const LLViewerTexture* baked_img = getImage( texture_data.mTextureIndex, 0 );  			if (!baked_img || !baked_img->hasGLTexture())  			{ +				lldebugs << "Texture at index " << i << " (texture index is " << texture_data.mTextureIndex << ") is not loaded" << llendl;  				return TRUE;  			}  		} +		lldebugs << "Avatar de-clouded" << llendl;  	}  	return FALSE;  } @@ -2258,6 +2264,7 @@ void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid )  	}  } +// FIXME: This is never called. Something may be broken.  void LLVOAvatarSelf::outputRezDiagnostics() const  {  	if(!gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime")) @@ -2315,6 +2322,18 @@ void LLVOAvatarSelf::outputRezDiagnostics() const  	}  } +void LLVOAvatarSelf::outputRezTiming(const std::string& msg) const +{ +	LL_DEBUGS("Avatar Rez") +		<< llformat("%s. Time from avatar creation: %.2f", msg.c_str(), mDebugSelfLoadTimer.getElapsedTimeF32()) +		<< llendl; +} + +void LLVOAvatarSelf::reportAvatarRezTime() const +{ +	// TODO: report mDebugSelfLoadTimer.getElapsedTimeF32() somehow. +} +  //-----------------------------------------------------------------------------  // setCachedBakedTexture()  // A baked texture id was received from a cache query, make it active diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 74ff47a3e4..54dbe81993 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -41,6 +41,7 @@ struct LocalTextureData;  class LLVOAvatarSelf :  	public LLVOAvatar  { +	LOG_CLASS(LLVOAvatarSelf);  /********************************************************************************   **                                                                            ** @@ -358,6 +359,8 @@ public:  	void 					debugWearablesLoaded() { mDebugTimeWearablesLoaded = mDebugSelfLoadTimer.getElapsedTimeF32(); }  	void 					debugAvatarVisible() { mDebugTimeAvatarVisible = mDebugSelfLoadTimer.getElapsedTimeF32(); }  	void 					outputRezDiagnostics() const; +	void					outputRezTiming(const std::string& msg) const; +	void					reportAvatarRezTime() const;  	void 					debugBakedTextureUpload(LLVOAvatarDefines::EBakedTextureIndex index, BOOL finished);  	static void				debugOnTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 920a9a3752..0da70d398b 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -305,6 +305,15 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)  	{  		mCurlRequest = new LLCurlEasyRequest();  	} +	if(!mCurlRequest->isValid()) +	{ +		llwarns << "mCurlRequest is invalid." << llendl ; + +		delete mCurlRequest ; +		mCurlRequest = NULL ; +		return ; +	} +  	mErrorCert = NULL;  //	mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // useful for debugging @@ -357,10 +366,20 @@ LLXMLRPCTransaction::Impl::~Impl()  	}  	delete mCurlRequest; +	mCurlRequest = NULL ;  }  bool LLXMLRPCTransaction::Impl::process()  { +	if(!mCurlRequest || !mCurlRequest->isValid()) +	{ +		llwarns << "transaction failed." << llendl ; + +		delete mCurlRequest ; +		mCurlRequest = NULL ; +		return true ; //failed, quit. +	} +  	switch(mStatus)  	{  		case LLXMLRPCTransaction::StatusComplete: diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 1d11abcf73..cd8550b00d 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -153,13 +153,6 @@           function="BuyCurrency" />        </menu_item_call>        <menu_item_call -         label="Merchant Outbox..." -         name="MerchantOutbox"> -        <menu_item_call.on_click -         function="Floater.ToggleOrBringToFront" -         parameter="outbox" /> -      </menu_item_call> -      <menu_item_call             label="Account dashboard..."             name="Manage My Account">          <menu_item_call.on_click diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index e88d1bf811..19ac418e9e 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -39,7 +39,7 @@  #include "llsdserialize.h"  #include "llthread.h"  #include "llupdaterservice.h" - +#include "llcurl.h"  class LLUpdateDownloader::Implementation:  	public LLThread @@ -198,13 +198,19 @@ LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client &  LLUpdateDownloader::Implementation::~Implementation()  { -	if(isDownloading()) { +	if(isDownloading())  +	{  		cancel();  		shutdown(); -	} else { +	}  +	else  +	{  		; // No op.  	} -	if(mCurl) curl_easy_cleanup(mCurl); +	if(mCurl) +	{ +		LLCurl::deleteEasyHandle(mCurl); +	}  } @@ -406,9 +412,12 @@ void LLUpdateDownloader::Implementation::run(void)  void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url, bool processHeader)  { -	if(mCurl == 0) { -		mCurl = curl_easy_init(); -	} else { +	if(mCurl == 0)  +	{ +		mCurl = LLCurl::newEasyHandle(); +	}  +	else  +	{  		curl_easy_reset(mCurl);  	} | 
