diff options
Diffstat (limited to 'indra/llcorehttp')
| -rwxr-xr-x | indra/llcorehttp/_httplibcurl.cpp | 198 | ||||
| -rwxr-xr-x | indra/llcorehttp/_httplibcurl.h | 12 | ||||
| -rwxr-xr-x | indra/llcorehttp/_httpoperation.cpp | 28 | ||||
| -rwxr-xr-x | indra/llcorehttp/_httpoprequest.cpp | 46 | ||||
| -rwxr-xr-x | indra/llcorehttp/_httppolicy.cpp | 83 | ||||
| -rwxr-xr-x | indra/llcorehttp/_httppolicy.h | 8 | ||||
| -rwxr-xr-x | indra/llcorehttp/_httpservice.cpp | 30 | 
7 files changed, 276 insertions, 129 deletions
| diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp index fb907f6318..b46833a1f3 100755 --- a/indra/llcorehttp/_httplibcurl.cpp +++ b/indra/llcorehttp/_httplibcurl.cpp @@ -40,6 +40,8 @@ namespace  void check_curl_multi_code(CURLMcode code);  void check_curl_multi_code(CURLMcode code, int curl_setopt_option); +static const char * const LOG_CORE("CoreHttp"); +  } // end anonymous namespace @@ -51,7 +53,8 @@ HttpLibcurl::HttpLibcurl(HttpService * service)  	: mService(service),  	  mPolicyCount(0),  	  mMultiHandles(NULL), -	  mActiveHandles(NULL) +	  mActiveHandles(NULL), +	  mDirtyPolicy(NULL)  {} @@ -90,6 +93,9 @@ void HttpLibcurl::shutdown()  		delete [] mActiveHandles;  		mActiveHandles = NULL; + +		delete [] mDirtyPolicy; +		mDirtyPolicy = NULL;  	}  	mPolicyCount = 0; @@ -101,44 +107,21 @@ void HttpLibcurl::start(int policy_count)  	llassert_always(policy_count <= HTTP_POLICY_CLASS_LIMIT);  	llassert_always(! mMultiHandles);					// One-time call only -	HttpPolicy & policy(mService->getPolicy());  	mPolicyCount = policy_count;  	mMultiHandles = new CURLM * [mPolicyCount];  	mActiveHandles = new int [mPolicyCount]; +	mDirtyPolicy = new bool [mPolicyCount];  	for (int policy_class(0); policy_class < mPolicyCount; ++policy_class)  	{ -		HttpPolicyClass & options(policy.getClassOptions(policy_class)); - -		mActiveHandles[policy_class] = 0;  		if (NULL == (mMultiHandles[policy_class] = curl_multi_init()))  		{ -			LL_ERRS("CoreHttp") << "Failed to allocate multi handle in libcurl." -								<< LL_ENDL; -		} -				 -		if (options.mPipelining > 1) -		{ -			CURLMcode code; -			 -			// We'll try to do pipelining on this multihandle -			code = curl_multi_setopt(mMultiHandles[policy_class], -									 CURLMOPT_PIPELINING, -									 1L); -			check_curl_multi_code(code, CURLMOPT_PIPELINING); -			code = curl_multi_setopt(mMultiHandles[policy_class], -									 CURLMOPT_MAX_PIPELINE_LENGTH, -									 long(options.mPipelining)); -			check_curl_multi_code(code, CURLMOPT_MAX_PIPELINE_LENGTH); -			code = curl_multi_setopt(mMultiHandles[policy_class], -									 CURLMOPT_MAX_HOST_CONNECTIONS, -									 long(options.mPerHostConnectionLimit)); -			check_curl_multi_code(code, CURLMOPT_MAX_HOST_CONNECTIONS); -			code = curl_multi_setopt(mMultiHandles[policy_class], -									 CURLMOPT_MAX_TOTAL_CONNECTIONS, -									 long(options.mConnectionLimit)); -			check_curl_multi_code(code, CURLMOPT_MAX_TOTAL_CONNECTIONS); +			LL_ERRS(LOG_CORE) << "Failed to allocate multi handle in libcurl." +							  << LL_ENDL;  		} +		mActiveHandles[policy_class] = 0; +		mDirtyPolicy[policy_class] = false; +		policyUpdated(policy_class);  	}  } @@ -156,8 +139,19 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport()  	// Give libcurl some cycles to do I/O & callbacks  	for (int policy_class(0); policy_class < mPolicyCount; ++policy_class)  	{ -		if (! mActiveHandles[policy_class] || ! mMultiHandles[policy_class]) +		if (! mMultiHandles[policy_class])  		{ +			// No handle, nothing to do. +			continue; +		} +		if (! mActiveHandles[policy_class]) +		{ +			// If we've gone quiet and there's a dirty update, apply it, +			// otherwise we're done. +			if (mDirtyPolicy[policy_class]) +			{ +				policyUpdated(policy_class); +			}  			continue;  		} @@ -192,9 +186,9 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport()  			}  			else  			{ -				LL_WARNS_ONCE("CoreHttp") << "Unexpected message from libcurl.  Msg code:  " -										  << msg->msg -										  << LL_ENDL; +				LL_WARNS_ONCE(LOG_CORE) << "Unexpected message from libcurl.  Msg code:  " +										<< msg->msg +										<< LL_ENDL;  			}  			msgs_in_queue = 0;  		} @@ -230,11 +224,11 @@ void HttpLibcurl::addOp(HttpOpRequest * op)  	{  		HttpPolicy & policy(mService->getPolicy()); -		LL_INFOS("CoreHttp") << "TRACE, ToActiveQueue, Handle:  " -							 << static_cast<HttpHandle>(op) -							 << ", Actives:  " << mActiveOps.size() -							 << ", Readies:  " << policy.getReadyCount(op->mReqPolicy) -							 << LL_ENDL; +		LL_INFOS(LOG_CORE) << "TRACE, ToActiveQueue, Handle:  " +						   << static_cast<HttpHandle>(op) +						   << ", Actives:  " << mActiveOps.size() +						   << ", Readies:  " << policy.getReadyCount(op->mReqPolicy) +						   << LL_ENDL;  	}  	// On success, make operation active @@ -286,10 +280,10 @@ void HttpLibcurl::cancelRequest(HttpOpRequest * op)  	// Tracing  	if (op->mTracing > HTTP_TRACE_OFF)  	{ -		LL_INFOS("CoreHttp") << "TRACE, RequestCanceled, Handle:  " -							 << static_cast<HttpHandle>(op) -							 << ", Status:  " << op->mStatus.toTerseString() -							 << LL_ENDL; +		LL_INFOS(LOG_CORE) << "TRACE, RequestCanceled, Handle:  " +						   << static_cast<HttpHandle>(op) +						   << ", Status:  " << op->mStatus.toTerseString() +						   << LL_ENDL;  	}  	// Cancel op and deliver for notification @@ -306,18 +300,18 @@ bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode  	if (handle != op->mCurlHandle || ! op->mCurlActive)  	{ -		LL_WARNS("CoreHttp") << "libcurl handle and HttpOpRequest handle in disagreement or inactive request." -							 << "  Handle:  " << static_cast<HttpHandle>(handle) -							 << LL_ENDL; +		LL_WARNS(LOG_CORE) << "libcurl handle and HttpOpRequest handle in disagreement or inactive request." +						   << "  Handle:  " << static_cast<HttpHandle>(handle) +						   << LL_ENDL;  		return false;  	}  	active_set_t::iterator it(mActiveOps.find(op));  	if (mActiveOps.end() == it)  	{ -		LL_WARNS("CoreHttp") << "libcurl completion for request not on active list.  Continuing." -							 << "  Handle:  " << static_cast<HttpHandle>(handle) -							 << LL_ENDL; +		LL_WARNS(LOG_CORE) << "libcurl completion for request not on active list.  Continuing." +						   << "  Handle:  " << static_cast<HttpHandle>(handle) +						   << LL_ENDL;  		return false;  	} @@ -348,9 +342,9 @@ bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode  		}  		else  		{ -			LL_WARNS("CoreHttp") << "Invalid HTTP response code (" -								 << http_status << ") received from server." -								 << LL_ENDL; +			LL_WARNS(LOG_CORE) << "Invalid HTTP response code (" +							   << http_status << ") received from server." +							   << LL_ENDL;  			op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INVALID_HTTP_STATUS);  		}  	} @@ -363,10 +357,10 @@ bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode  	// Tracing  	if (op->mTracing > HTTP_TRACE_OFF)  	{ -		LL_INFOS("CoreHttp") << "TRACE, RequestComplete, Handle:  " -							 << static_cast<HttpHandle>(op) -							 << ", Status:  " << op->mStatus.toTerseString() -							 << LL_ENDL; +		LL_INFOS(LOG_CORE) << "TRACE, RequestComplete, Handle:  " +						   << static_cast<HttpHandle>(op) +						   << ", Status:  " << op->mStatus.toTerseString() +						   << LL_ENDL;  	}  	// Dispatch to next stage @@ -390,6 +384,88 @@ int HttpLibcurl::getActiveCountInClass(int policy_class) const  	return mActiveHandles ? mActiveHandles[policy_class] : 0;  } +void HttpLibcurl::policyUpdated(int policy_class) +{ +	if (policy_class < 0 || policy_class >= mPolicyCount || ! mMultiHandles) +	{ +		return; +	} +	 +	HttpPolicy & policy(mService->getPolicy()); +	 +	if (! mActiveHandles[policy_class]) +	{ +		// Clear to set options.  As of libcurl 7.37.0, if a pipelining +		// multi handle has active requests and you try to set the +		// multi handle to non-pipelining, the library gets very angry +		// and goes off the rails corrupting memory.  A clue that you're +		// about to crash is that you'll get a missing server response +		// error (curl code 9).  So, if options are to be set, we let +		// the multi handle run out of requests, then set options, and +		// re-enable request processing. +		// +		// All of this stall mechanism exists for this reason.  If +		// libcurl becomes more resilient later, it should be possible +		// to remove all of this.  The connection limit settings are fine, +		// it's just that pipelined-to-non-pipelined transition that +		// is fatal at the moment. +		 +		HttpPolicyClass & options(policy.getClassOptions(policy_class)); +		CURLM * multi_handle(mMultiHandles[policy_class]); +		CURLMcode code; + +		// Enable policy if stalled +		policy.stallPolicy(policy_class, false); +		mDirtyPolicy[policy_class] = false; +		 +		if (options.mPipelining > 1) +		{ +			// We'll try to do pipelining on this multihandle +			code = curl_multi_setopt(multi_handle, +									 CURLMOPT_PIPELINING, +									 1L); +			check_curl_multi_code(code, CURLMOPT_PIPELINING); +			code = curl_multi_setopt(multi_handle, +									 CURLMOPT_MAX_PIPELINE_LENGTH, +									 long(options.mPipelining)); +			check_curl_multi_code(code, CURLMOPT_MAX_PIPELINE_LENGTH); +			code = curl_multi_setopt(multi_handle, +									 CURLMOPT_MAX_HOST_CONNECTIONS, +									 long(options.mPerHostConnectionLimit)); +			check_curl_multi_code(code, CURLMOPT_MAX_HOST_CONNECTIONS); +			code = curl_multi_setopt(multi_handle, +									 CURLMOPT_MAX_TOTAL_CONNECTIONS, +									 long(options.mConnectionLimit)); +			check_curl_multi_code(code, CURLMOPT_MAX_TOTAL_CONNECTIONS); +		} +		else +		{ +			code = curl_multi_setopt(multi_handle, +									 CURLMOPT_PIPELINING, +									 0L); +			check_curl_multi_code(code, CURLMOPT_PIPELINING); +			code = curl_multi_setopt(multi_handle, +									 CURLMOPT_MAX_HOST_CONNECTIONS, +									 0L); +			check_curl_multi_code(code, CURLMOPT_MAX_HOST_CONNECTIONS); +			code = curl_multi_setopt(multi_handle, +									 CURLMOPT_MAX_TOTAL_CONNECTIONS, +									 long(options.mConnectionLimit)); +			check_curl_multi_code(code, CURLMOPT_MAX_TOTAL_CONNECTIONS); +		} +	} +	else if (! mDirtyPolicy[policy_class]) +	{ +		// Mark policy dirty and request a stall in the policy. +		// When policy goes idle, we'll re-invoke this method +		// and perform the change.  Don't allow this thread to +		// sleep while we're waiting for quiescence, we'll just +		// stop processing. +		mDirtyPolicy[policy_class] = true; +		policy.stallPolicy(policy_class, true); +	} +} +  // ---------------------------------------  // Free functions @@ -424,9 +500,9 @@ void check_curl_multi_code(CURLMcode code, int curl_setopt_option)  {  	if (CURLM_OK != code)  	{ -		LL_WARNS("CoreHttp") << "libcurl multi error detected:  " << curl_multi_strerror(code) -							 << ", curl_multi_setopt option:  " << curl_setopt_option -							 << LL_ENDL; +		LL_WARNS(LOG_CORE) << "libcurl multi error detected:  " << curl_multi_strerror(code) +						   << ", curl_multi_setopt option:  " << curl_setopt_option +						   << LL_ENDL;  	}  } @@ -435,8 +511,8 @@ void check_curl_multi_code(CURLMcode code)  {  	if (CURLM_OK != code)  	{ -		LL_WARNS("CoreHttp") << "libcurl multi error detected:  " << curl_multi_strerror(code) -							 << LL_ENDL; +		LL_WARNS(LOG_CORE) << "libcurl multi error detected:  " << curl_multi_strerror(code) +						   << LL_ENDL;  	}  } diff --git a/indra/llcorehttp/_httplibcurl.h b/indra/llcorehttp/_httplibcurl.h index 67f98dd4f0..2c7ad1fa8e 100755 --- a/indra/llcorehttp/_httplibcurl.h +++ b/indra/llcorehttp/_httplibcurl.h @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2012&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012-2013, Linden Research, Inc. + * Copyright (C) 2012-2014, 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 @@ -116,6 +116,14 @@ public:  	/// Threading:  called by worker thread.  	bool cancel(HttpHandle handle); +	/// Informs transport that a particular policy class has had +	/// options changed and so should effect any transport state +	/// change necessary to effect those changes.  Used mainly for +	/// initialization and dynamic option setting. +	/// +	/// Threading:  called by worker thread. +	void policyUpdated(int policy_class); +  protected:  	/// Invoked when libcurl has indicated a request has been processed  	/// to completion and we need to move the request to a new state. @@ -134,6 +142,8 @@ protected:  	int					mPolicyCount;  	CURLM **			mMultiHandles;			// One handle per policy class  	int *				mActiveHandles;			// Active count per policy class +	bool *				mDirtyPolicy;			// Dirty policy update waiting for stall (per pc) +	  }; // end class HttpLibcurl  }  // end namespace LLCore diff --git a/indra/llcorehttp/_httpoperation.cpp b/indra/llcorehttp/_httpoperation.cpp index 5bb0654652..fefe561f80 100755 --- a/indra/llcorehttp/_httpoperation.cpp +++ b/indra/llcorehttp/_httpoperation.cpp @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2012&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012-2013, Linden Research, Inc. + * Copyright (C) 2012-2014, 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 @@ -38,6 +38,14 @@  #include "lltimer.h" +namespace +{ + +static const char * const LOG_CORE("CoreHttp"); + +} // end anonymous namespace + +  namespace LLCore  { @@ -94,8 +102,8 @@ void HttpOperation::stageFromRequest(HttpService *)  	// Default implementation should never be called.  This  	// indicates an operation making a transition that isn't  	// defined. -	LL_ERRS("CoreHttp") << "Default stageFromRequest method may not be called." -						<< LL_ENDL; +	LL_ERRS(LOG_CORE) << "Default stageFromRequest method may not be called." +					  << LL_ENDL;  } @@ -104,8 +112,8 @@ void HttpOperation::stageFromReady(HttpService *)  	// Default implementation should never be called.  This  	// indicates an operation making a transition that isn't  	// defined. -	LL_ERRS("CoreHttp") << "Default stageFromReady method may not be called." -						<< LL_ENDL; +	LL_ERRS(LOG_CORE) << "Default stageFromReady method may not be called." +					  << LL_ENDL;  } @@ -114,8 +122,8 @@ void HttpOperation::stageFromActive(HttpService *)  	// Default implementation should never be called.  This  	// indicates an operation making a transition that isn't  	// defined. -	LL_ERRS("CoreHttp") << "Default stageFromActive method may not be called." -						<< LL_ENDL; +	LL_ERRS(LOG_CORE) << "Default stageFromActive method may not be called." +					  << LL_ENDL;  } @@ -145,9 +153,9 @@ void HttpOperation::addAsReply()  {  	if (mTracing > HTTP_TRACE_OFF)  	{ -		LL_INFOS("CoreHttp") << "TRACE, ToReplyQueue, Handle:  " -							 << static_cast<HttpHandle>(this) -							 << LL_ENDL; +		LL_INFOS(LOG_CORE) << "TRACE, ToReplyQueue, Handle:  " +						   << static_cast<HttpHandle>(this) +						   << LL_ENDL;  	}  	if (mReplyQueue) diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 43dd069bc6..eb664fdced 100755 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2012&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012-2013, Linden Research, Inc. + * Copyright (C) 2012-2014, 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 @@ -94,6 +94,8 @@ void os_strlower(char * str);  void check_curl_easy_code(CURLcode code);  void check_curl_easy_code(CURLcode code, int curl_setopt_option); +static const char * const LOG_CORE("CoreHttp"); +  } // end anonymous namespace @@ -416,8 +418,8 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  	if (! mCurlHandle)  	{  		// We're in trouble.  We'll continue but it won't go well. -		LL_WARNS("CoreHttp") << "Failed to allocate libcurl easy handle.  Continuing." -							 << LL_ENDL; +		LL_WARNS(LOG_CORE) << "Failed to allocate libcurl easy handle.  Continuing." +						   << LL_ENDL;  		return HttpStatus(HttpStatus::LLCORE, HE_BAD_ALLOC);  	}  	code = curl_easy_setopt(mCurlHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); @@ -538,9 +540,9 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  		break;  	default: -		LL_ERRS("CoreHttp") << "Invalid HTTP method in request:  " -							<< int(mReqMethod)  << ".  Can't recover." -							<< LL_ENDL; +		LL_ERRS(LOG_CORE) << "Invalid HTTP method in request:  " +						  << int(mReqMethod)  << ".  Can't recover." +						  << LL_ENDL;  		break;  	} @@ -652,8 +654,8 @@ size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void  		{  			// Warn but continue if the read position moves beyond end-of-body  			// for some reason. -			LL_WARNS("CoreHttp") << "Request body position beyond body size.  Truncating request body." -								 << LL_ENDL; +			LL_WARNS(LOG_CORE) << "Request body position beyond body size.  Truncating request body." +							   << LL_ENDL;  		}  		return 0;  	} @@ -790,10 +792,10 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi  		else  		{  			// Ignore the unparsable. -			LL_INFOS_ONCE("CoreHttp") << "Problem parsing odd Content-Range header:  '" -									  << std::string(hdr_data, wanted_hdr_size) -									  << "'.  Ignoring." -									  << LL_ENDL; +			LL_INFOS_ONCE(LOG_CORE) << "Problem parsing odd Content-Range header:  '" +									<< std::string(hdr_data, wanted_hdr_size) +									<< "'.  Ignoring." +									<< LL_ENDL;  		}  	} @@ -895,11 +897,11 @@ int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffe  	if (logit)  	{ -		LL_INFOS("CoreHttp") << "TRACE, LibcurlDebug, Handle:  " -							 << static_cast<HttpHandle>(op) -							 << ", Type:  " << tag -							 << ", Data:  " << safe_line -							 << LL_ENDL; +		LL_INFOS(LOG_CORE) << "TRACE, LibcurlDebug, Handle:  " +						   << static_cast<HttpHandle>(op) +						   << ", Type:  " << tag +						   << ", Data:  " << safe_line +						   << LL_ENDL;  	}  	return 0; @@ -1094,9 +1096,9 @@ void check_curl_easy_code(CURLcode code, int curl_setopt_option)  		//  		// linux appears to throw a curl error once per session for a bad initialization  		// at a pretty random time (when enabling cookies). -		LL_WARNS("CoreHttp") << "libcurl error detected:  " << curl_easy_strerror(code) -							 << ", curl_easy_setopt option:  " << curl_setopt_option -							 << LL_ENDL; +		LL_WARNS(LOG_CORE) << "libcurl error detected:  " << curl_easy_strerror(code) +						   << ", curl_easy_setopt option:  " << curl_setopt_option +						   << LL_ENDL;  	}  } @@ -1109,8 +1111,8 @@ void check_curl_easy_code(CURLcode code)  		//  		// linux appears to throw a curl error once per session for a bad initialization  		// at a pretty random time (when enabling cookies). -		LL_WARNS("CoreHttp") << "libcurl error detected:  " << curl_easy_strerror(code) -							 << LL_ENDL; +		LL_WARNS(LOG_CORE) << "libcurl error detected:  " << curl_easy_strerror(code) +						   << LL_ENDL;  	}  } diff --git a/indra/llcorehttp/_httppolicy.cpp b/indra/llcorehttp/_httppolicy.cpp index bb7959b578..09b9206f63 100755 --- a/indra/llcorehttp/_httppolicy.cpp +++ b/indra/llcorehttp/_httppolicy.cpp @@ -35,6 +35,13 @@  #include "lltimer.h" +namespace +{ + +static const char * const LOG_CORE("CoreHttp"); + +} // end anonymous namespace +  namespace LLCore  { @@ -51,7 +58,8 @@ public:  	ClassState()  		: mThrottleEnd(0),  		  mThrottleLeft(0L), -		  mRequestCount(0L) +		  mRequestCount(0L), +		  mStallStaging(false)  		{}  	HttpReadyQueue		mReadyQueue; @@ -61,6 +69,7 @@ public:  	HttpTime			mThrottleEnd;  	long				mThrottleLeft;  	long				mRequestCount; +	bool				mStallStaging;  }; @@ -171,19 +180,19 @@ void HttpPolicy::retryOp(HttpOpRequest * op)  	{  		++op->mPolicy503Retries;  	} -	LL_DEBUGS("CoreHttp") << "HTTP request " << static_cast<HttpHandle>(op) -						  << " retry " << op->mPolicyRetries -						  << " scheduled in " << (delta / HttpTime(1000)) -						  << " mS (" << (external_delta ? "external" : "internal") -						  << ").  Status:  " << op->mStatus.toTerseString() -						  << LL_ENDL; +	LL_DEBUGS(LOG_CORE) << "HTTP request " << static_cast<HttpHandle>(op) +						<< " retry " << op->mPolicyRetries +						<< " scheduled in " << (delta / HttpTime(1000)) +						<< " mS (" << (external_delta ? "external" : "internal") +						<< ").  Status:  " << op->mStatus.toTerseString() +						<< LL_ENDL;  	if (op->mTracing > HTTP_TRACE_OFF)  	{ -		LL_INFOS("CoreHttp") << "TRACE, ToRetryQueue, Handle:  " -							 << static_cast<HttpHandle>(op) -							 << ", Delta:  " << (delta / HttpTime(1000)) -							 << ", Retries:  " << op->mPolicyRetries -							 << LL_ENDL; +		LL_INFOS(LOG_CORE) << "TRACE, ToRetryQueue, Handle:  " +						   << static_cast<HttpHandle>(op) +						   << ", Delta:  " << (delta / HttpTime(1000)) +						   << ", Retries:  " << op->mPolicyRetries +						   << LL_ENDL;  	}  	mClasses[policy_class]->mRetryQueue.push(op);  } @@ -219,6 +228,15 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue()  		HttpRetryQueue & retryq(state.mRetryQueue);  		HttpReadyQueue & readyq(state.mReadyQueue); +		if (state.mStallStaging) +		{ +			// Stalling but don't sleep.  Need to complete operations +			// and get back to servicing queues.  Do this test before +			// the retryq/readyq test or you'll get stalls until you +			// click a setting or an asset request comes in. +			result = HttpService::NORMAL; +			continue; +		}  		if (retryq.empty() && readyq.empty())  		{  			continue; @@ -262,9 +280,9 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue()  					if (now >= state.mThrottleEnd)  					{  						// Throttle expired, move to next window -						LL_DEBUGS("CoreHttp") << "Throttle expired with " << state.mThrottleLeft -											  << " requests to go and " << state.mRequestCount -											  << " requests issued." << LL_ENDL; +						LL_DEBUGS(LOG_CORE) << "Throttle expired with " << state.mThrottleLeft +											<< " requests to go and " << state.mRequestCount +											<< " requests issued." << LL_ENDL;  						state.mThrottleLeft = state.mOptions.mThrottleRate;  						state.mThrottleEnd = now + HttpTime(1000000);  					} @@ -291,9 +309,9 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue()  					if (now >= state.mThrottleEnd)  					{  						// Throttle expired, move to next window -						LL_DEBUGS("CoreHttp") << "Throttle expired with " << state.mThrottleLeft -											  << " requests to go and " << state.mRequestCount -											  << " requests issued." << LL_ENDL; +						LL_DEBUGS(LOG_CORE) << "Throttle expired with " << state.mThrottleLeft +											<< " requests to go and " << state.mRequestCount +											<< " requests issued." << LL_ENDL;  						state.mThrottleLeft = state.mOptions.mThrottleRate;  						state.mThrottleEnd = now + HttpTime(1000000);  					} @@ -408,17 +426,17 @@ bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op)  	// This op is done, finalize it delivering it to the reply queue...  	if (! op->mStatus)  	{ -		LL_WARNS("CoreHttp") << "HTTP request " << static_cast<HttpHandle>(op) -							 << " failed after " << op->mPolicyRetries -							 << " retries.  Reason:  " << op->mStatus.toString() -							 << " (" << op->mStatus.toTerseString() << ")" -							 << LL_ENDL; +		LL_WARNS(LOG_CORE) << "HTTP request " << static_cast<HttpHandle>(op) +						   << " failed after " << op->mPolicyRetries +						   << " retries.  Reason:  " << op->mStatus.toString() +						   << " (" << op->mStatus.toTerseString() << ")" +						   << LL_ENDL;  	}  	else if (op->mPolicyRetries)  	{ -		LL_DEBUGS("CoreHttp") << "HTTP request " << static_cast<HttpHandle>(op) -							  << " succeeded on retry " << op->mPolicyRetries << "." -							  << LL_ENDL; +		LL_DEBUGS(LOG_CORE) << "HTTP request " << static_cast<HttpHandle>(op) +							<< " succeeded on retry " << op->mPolicyRetries << "." +							<< LL_ENDL;  	}  	op->stageFromActive(mService); @@ -446,4 +464,17 @@ int HttpPolicy::getReadyCount(HttpRequest::policy_t policy_class) const  } +bool HttpPolicy::stallPolicy(HttpRequest::policy_t policy_class, bool stall) +{ +	bool ret(false); +	 +	if (policy_class < mClasses.size()) +	{ +		ret = mClasses[policy_class]->mStallStaging; +		mClasses[policy_class]->mStallStaging = stall; +	} +	return ret; +} + +  }  // end namespace LLCore diff --git a/indra/llcorehttp/_httppolicy.h b/indra/llcorehttp/_httppolicy.h index bf1aa74267..11cd89bbd1 100755 --- a/indra/llcorehttp/_httppolicy.h +++ b/indra/llcorehttp/_httppolicy.h @@ -158,6 +158,14 @@ public:  	/// Threading:  called by worker thread  	int getReadyCount(HttpRequest::policy_t policy_class) const; +	/// Stall (or unstall) a policy class preventing requests from +	/// transitioning to an active state.  Used to allow an HTTP +	/// request policy to empty prior to changing settings or state +	/// that isn't tolerant of changes when work is outstanding. +	/// +	/// Threading:  called by worker thread +	bool stallPolicy(HttpRequest::policy_t policy_class, bool stall); +	  protected:  	struct ClassState;  	typedef std::vector<ClassState *>	class_list_t; diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index c94249dc2d..c673e1be1d 100755 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2012&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012-2013, Linden Research, Inc. + * Copyright (C) 2012-2014, 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 @@ -40,6 +40,14 @@  #include "llthread.h" +namespace +{ + +static const char * const LOG_CORE("CoreHttp"); + +} // end anonymous namespace + +  namespace LLCore  { @@ -87,8 +95,8 @@ HttpService::~HttpService()  				// Failed to join, expect problems ahead so do a hard termination.  				mThread->cancel(); -				LL_WARNS("CoreHttp") << "Destroying HttpService with running thread.  Expect problems." -									 << LL_ENDL; +				LL_WARNS(LOG_CORE) << "Destroying HttpService with running thread.  Expect problems." +								   << LL_ENDL;  			}  		}  	} @@ -328,9 +336,9 @@ HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop)  			if (op->mTracing > HTTP_TRACE_OFF)  			{ -				LL_INFOS("CoreHttp") << "TRACE, FromRequestQueue, Handle:  " -									 << static_cast<HttpHandle>(op) -									 << LL_ENDL; +				LL_INFOS(LOG_CORE) << "TRACE, FromRequestQueue, Handle:  " +								   << static_cast<HttpHandle>(op) +								   << LL_ENDL;  			}  			// Stage @@ -437,9 +445,13 @@ HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ  		HttpPolicyClass & opts(mPolicy->getClassOptions(pclass));  		status = opts.set(opt, value); -		if (status && ret_value) +		if (status)  		{ -			status = opts.get(opt, ret_value); +			mTransport->policyUpdated(pclass); +			if (ret_value) +			{ +				status = opts.get(opt, ret_value); +			}  		}  	} @@ -463,7 +475,7 @@ HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ  		return status;  	} -	// Only string values are global at this time +	// String values are always global (at this time).  	if (pclass == HttpRequest::GLOBAL_POLICY_ID)  	{  		HttpPolicyGlobal & opts(mPolicy->getGlobalOptions()); | 
