Monty Brandenberg avatar Monty Brandenberg committed 70220bd

SH-3280 Better init/shutdown functionality for llcorehttp by llappviewer
Isolate llcorehttp initialization into a utility class (LLAppCoreHttp)
that provides glue between app and library (sets up policies, handles
notifications). Introduce 'TextureFetchConcurrency' debug setting to
provide some field control when absolutely necessary.

Comments (0)

Files changed (8)

indra/newview/CMakeLists.txt

     llagentwearables.cpp
     llagentwearablesfetch.cpp
     llanimstatelabels.cpp
+    llappcorehttp.cpp
     llappearancemgr.cpp
     llappviewer.cpp
     llappviewerlistener.cpp
     llagentwearables.h
     llagentwearablesfetch.h
     llanimstatelabels.h
+    llappcorehttp.h
     llappearance.h
     llappearancemgr.h
     llappviewer.h

indra/newview/app_settings/settings.xml

       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>TextureFetchConcurrency</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum number of HTTP connections used for texture fetches</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>U32</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>TextureFetchDebuggerEnabled</key>
     <map>
       <key>Comment</key>

indra/newview/llappcorehttp.cpp

+/**
+ * @file llappcorehttp.cpp
+ * @brief 
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llappcorehttp.h"
+
+#include "llviewercontrol.h"
+
+
+const F64 LLAppCoreHttp::MAX_THREAD_WAIT_TIME(10.0);
+
+LLAppCoreHttp::LLAppCoreHttp()
+	: mRequest(NULL),
+	  mStopHandle(LLCORE_HTTP_HANDLE_INVALID),
+	  mStopRequested(0.0),
+	  mStopped(false),
+	  mPolicyDefault(-1)
+{}
+
+
+LLAppCoreHttp::~LLAppCoreHttp()
+{
+	delete mRequest;
+	mRequest = NULL;
+}
+
+
+void LLAppCoreHttp::init()
+{
+	LLCore::HttpStatus status = LLCore::HttpRequest::createService();
+	if (! status)
+	{
+		LL_ERRS("Init") << "Failed to initialize HTTP services.  Reason:  "
+						<< status.toString()
+						<< LL_ENDL;
+	}
+
+	// Point to our certs or SSH/https: will fail on connect
+	status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_CA_FILE,
+														gDirUtilp->getCAFile());
+	if (! status)
+	{
+		LL_ERRS("Init") << "Failed to set CA File for HTTP services.  Reason:  "
+						<< status.toString()
+						<< LL_ENDL;
+	}
+
+	// Establish HTTP Proxy.  "LLProxy" is a special string which directs
+	// the code to use LLProxy::applyProxySettings() to establish any
+	// HTTP or SOCKS proxy for http operations.
+	status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_LLPROXY, 1);
+	if (! status)
+	{
+		LL_ERRS("Init") << "Failed to set HTTP proxy for HTTP services.  Reason:  "
+						<< status.toString()
+						<< LL_ENDL;
+	}
+
+	// Tracing levels for library & libcurl (note that 2 & 3 are beyond spammy):
+	// 0 - None
+	// 1 - Basic start, stop simple transitions
+	// 2 - libcurl CURLOPT_VERBOSE mode with brief lines
+	// 3 - with partial data content
+	status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 0);
+
+	// Setup default policy and constrain if directed to
+	mPolicyDefault = LLCore::HttpRequest::DEFAULT_POLICY_ID;
+	static const std::string texture_concur("TextureFetchConcurrency");
+	if (gSavedSettings.controlExists(texture_concur))
+	{
+		U32 concur(llmin(gSavedSettings.getU32(texture_concur), U32(12)));
+
+		if (concur > 0)
+		{
+			LLCore::HttpStatus status;
+			status = LLCore::HttpRequest::setPolicyClassOption(mPolicyDefault,
+															   LLCore::HttpRequest::CP_CONNECTION_LIMIT,
+															   concur);
+			if (! status)
+			{
+				LL_WARNS("Init") << "Unable to set texture fetch concurrency.  Reason:  "
+								 << status.toString()
+								 << LL_ENDL;
+			}
+			else
+			{
+				LL_INFOS("Init") << "Application settings overriding default texture fetch concurrency.  New value:  "
+								 << concur
+								 << LL_ENDL;
+			}
+		}
+	}
+	
+	// Kick the thread
+	status = LLCore::HttpRequest::startThread();
+	if (! status)
+	{
+		LL_ERRS("Init") << "Failed to start HTTP servicing thread.  Reason:  "
+						<< status.toString()
+						<< LL_ENDL;
+	}
+
+	mRequest = new LLCore::HttpRequest;
+}
+
+
+void LLAppCoreHttp::requestStop()
+{
+	llassert_always(mRequest);
+
+	mStopHandle = mRequest->requestStopThread(this);
+	if (LLCORE_HTTP_HANDLE_INVALID != mStopHandle)
+	{
+		mStopRequested = LLTimer::getTotalSeconds();
+	}
+}
+
+
+void LLAppCoreHttp::cleanup()
+{
+	if (LLCORE_HTTP_HANDLE_INVALID == mStopHandle)
+	{
+		// Should have been started already...
+		requestStop();
+	}
+	
+	if (LLCORE_HTTP_HANDLE_INVALID == mStopHandle)
+	{
+		LL_WARNS("Cleanup") << "Attempting to cleanup HTTP services without thread shutdown"
+							<< LL_ENDL;
+	}
+	else
+	{
+		while (! mStopped && LLTimer::getTotalSeconds() < (mStopRequested + MAX_THREAD_WAIT_TIME))
+		{
+			mRequest->update(200000);
+			ms_sleep(50);
+		}
+		if (! mStopped)
+		{
+			LL_WARNS("Cleanup") << "Attempting to cleanup HTTP services with thread shutdown incomplete"
+								<< LL_ENDL;
+		}
+	}
+
+	delete mRequest;
+	mRequest = NULL;
+
+	LLCore::HttpStatus status = LLCore::HttpRequest::destroyService();
+	if (! status)
+	{
+		LL_WARNS("Cleanup") << "Failed to shutdown HTTP services, continuing.  Reason:  "
+							<< status.toString()
+							<< LL_ENDL;
+	}
+}
+
+
+void LLAppCoreHttp::onCompleted(LLCore::HttpHandle, LLCore::HttpResponse *)
+{
+	mStopped = true;
+}

indra/newview/llappcorehttp.h

+/**
+ * @file llappcorehttp.h
+ * @brief Singleton initialization/shutdown class for llcorehttp library
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef	_LL_APP_COREHTTP_H_
+#define	_LL_APP_COREHTTP_H_
+
+
+#include "httprequest.h"
+#include "httphandler.h"
+#include "httpresponse.h"
+
+
+// This class manages the lifecyle of the core http library.
+// Slightly different style than traditional code but reflects
+// the use of handler classes and light-weight interface
+// object instances of the new libraries.  To be used
+// as a singleton and static construction is fine.
+class LLAppCoreHttp : public LLCore::HttpHandler
+{
+public:
+	LLAppCoreHttp();
+	~LLAppCoreHttp();
+	
+	// Initialize the LLCore::HTTP library creating service classes
+	// and starting the servicing thread.  Caller is expected to do
+	// other initializations (SSL mutex, thread hash function) appropriate
+	// for the application.
+	void init();
+
+	// Request that the servicing thread stop servicing requests,
+	// release resource references and stop.  Request is asynchronous
+	// and @see cleanup() will perform a limited wait loop for this
+	// request to stop the thread.
+	void requestStop();
+	
+	// Terminate LLCore::HTTP library services.  Caller is expected
+	// to have made a best-effort to shutdown the servicing thread
+	// by issuing a requestThreadStop() and waiting for completion
+	// notification that the stop has completed.
+	void cleanup();
+
+	// Notification when the stop request is complete.
+	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+	// Retrieve the policy class for default operations.
+	int getPolicyDefault() const
+		{
+			return mPolicyDefault;
+		}
+	
+private:
+	static const F64			MAX_THREAD_WAIT_TIME;
+	
+private:
+	LLCore::HttpRequest *		mRequest;
+	LLCore::HttpHandle			mStopHandle;
+	F64							mStopRequested;
+	bool						mStopped;
+	int							mPolicyDefault;
+};
+
+
+#endif	// _LL_APP_COREHTTP_H_

indra/newview/llappviewer.cpp

 #include "llmachineid.h"
 #include "llmainlooprepeater.h"
 
-// LLCore::HTTP
-#include "httpcommon.h"
-#include "httprequest.h"
-#include "httphandler.h"
 
 // *FIX: These extern globals should be cleaned up.
 // The globals either represent state/config/resource-storage of either 
 // Used on Win32 for other apps to identify our window (eg, win_setup)
 const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
 
-namespace
-{
-
-// This class manages the lifecyle of the core http library.
-// Slightly different style than traditional code but reflects
-// the use of handler classes and light-weight interface
-// object instances of the new libraries.  To be used
-// as a singleton and static construction is fine.
-class CoreHttp : public LLCore::HttpHandler
-{
-public:
-	CoreHttp();
-	~CoreHttp();
-	
-	// Initialize the LLCore::HTTP library creating service classes
-	// and starting the servicing thread.  Caller is expected to do
-	// other initializations (SSL mutex, thread hash function) appropriate
-	// for the application.
-	void init();
-
-	// Request that the servicing thread stop servicing requests,
-	// release resource references and stop.
-	void requestStop();
-	
-	// Terminate LLCore::HTTP library services.  Caller is expected
-	// to have made a best-effort to shutdown the servicing thread
-	// by issuing a requestThreadStop() and waiting for completion
-	// notification that the stop has completed.
-	void cleanup();
-
-	// Notification when the stop request is complete.
-	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
-
-private:
-	static const F64			MAX_THREAD_WAIT_TIME;
-	
-private:
-	LLCore::HttpRequest *		mRequest;
-	LLCore::HttpHandle			mStopHandle;
-	F64							mStopRequested;
-	bool						mStopped;
-};
-
-CoreHttp coreHttpLib;
-	
-}  // end anonymous namespace
-
 //-- LLDeferredTaskList ------------------------------------------------------
 
 /**
 	LLViewerStatsRecorder::initClass();
 #endif
 
-	// Initialize the non-LLCurl libcurl library
-	coreHttpLib.init();
+	// Initialize the non-LLCurl libcurl library.  Should be called
+	// before consumers (LLTextureFetch).
+	mAppCoreHttp.init();
 	
     // *NOTE:Mani - LLCurl::initClass is not thread safe. 
     // Called before threads are created.
 
 	// Delete workers first
 	// shotdown all worker threads before deleting them in case of co-dependencies
-	coreHttpLib.requestStop();
+	mAppCoreHttp.requestStop();
 	sTextureFetch->shutdown();
 	sTextureCache->shutdown();	
 	sImageDecodeThread->shutdown();
 	LLCurl::cleanupClass();
 
 	// Non-LLCurl libcurl library
-	coreHttpLib.cleanup();
+	mAppCoreHttp.cleanup();
 
 	// If we're exiting to launch an URL, do that here so the screen
 	// is at the right resolution before we launch IE.
 	gViewerAssetStatsMain->reset();
 }
 
-namespace
-{
-
-const F64 CoreHttp::MAX_THREAD_WAIT_TIME(10.0);
-
-CoreHttp::CoreHttp()
-	: mRequest(NULL),
-	  mStopHandle(LLCORE_HTTP_HANDLE_INVALID),
-	  mStopRequested(0.0),
-	  mStopped(false)
-{}
-
-
-CoreHttp::~CoreHttp()
-{
-	delete mRequest;
-	mRequest = NULL;
-}
-
-
-void CoreHttp::init()
-{
-	LLCore::HttpStatus status = LLCore::HttpRequest::createService();
-	if (! status)
-	{
-		LL_ERRS("Init") << "Failed to initialize HTTP services.  Reason:  "
-						<< status.toString()
-						<< LL_ENDL;
-	}
-
-	// Point to our certs or SSH/https: will fail on connect
-	status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_CA_FILE,
-														gDirUtilp->getCAFile());
-	if (! status)
-	{
-		LL_ERRS("Init") << "Failed to set CA File for HTTP services.  Reason:  "
-						<< status.toString()
-						<< LL_ENDL;
-	}
-
-	// Establish HTTP Proxy.  "LLProxy" is a special string which directs
-	// the code to use LLProxy::applyProxySettings() to establish any
-	// HTTP or SOCKS proxy for http operations.
-	status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_LLPROXY, 1);
-	if (! status)
-	{
-		LL_ERRS("Init") << "Failed to set HTTP proxy for HTTP services.  Reason:  "
-						<< status.toString()
-						<< LL_ENDL;
-	}
-
-	// Tracing levels for library & libcurl (note that 2 & 3 are beyond spammy):
-	// 0 - None
-	// 1 - Basic start, stop simple transitions
-	// 2 - libcurl CURLOPT_VERBOSE mode with brief lines
-	// 3 - with partial data content
-	status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 0);
-
-	// Kick the thread
-	status = LLCore::HttpRequest::startThread();
-	if (! status)
-	{
-		LL_ERRS("Init") << "Failed to start HTTP servicing thread.  Reason:  "
-						<< status.toString()
-						<< LL_ENDL;
-	}
-
-	mRequest = new LLCore::HttpRequest;
-}
-
-
-void CoreHttp::requestStop()
-{
-	llassert_always(mRequest);
-
-	mStopHandle = mRequest->requestStopThread(this);
-	if (LLCORE_HTTP_HANDLE_INVALID != mStopHandle)
-	{
-		mStopRequested = LLTimer::getTotalSeconds();
-	}
-}
-
-
-void CoreHttp::cleanup()
-{
-	if (LLCORE_HTTP_HANDLE_INVALID == mStopHandle)
-	{
-		// Should have been started already...
-		requestStop();
-	}
-	
-	if (LLCORE_HTTP_HANDLE_INVALID == mStopHandle)
-	{
-		LL_WARNS("Cleanup") << "Attempting to cleanup HTTP services without thread shutdown"
-							<< LL_ENDL;
-	}
-	else
-	{
-		while (! mStopped && LLTimer::getTotalSeconds() < (mStopRequested + MAX_THREAD_WAIT_TIME))
-		{
-			mRequest->update(200000);
-			ms_sleep(50);
-		}
-		if (! mStopped)
-		{
-			LL_WARNS("Cleanup") << "Attempting to cleanup HTTP services with thread shutdown incomplete"
-								<< LL_ENDL;
-		}
-	}
-
-	delete mRequest;
-	mRequest = NULL;
-
-	LLCore::HttpStatus status = LLCore::HttpRequest::destroyService();
-	if (! status)
-	{
-		LL_WARNS("Cleanup") << "Failed to shutdown HTTP services, continuing.  Reason:  "
-							<< status.toString()
-							<< LL_ENDL;
-	}
-}
-
-
-void CoreHttp::onCompleted(LLCore::HttpHandle, LLCore::HttpResponse *)
-{
-	mStopped = true;
-}
-
-}  // end anonymous namespace

indra/newview/llappviewer.h

 #include "llcontrol.h"
 #include "llsys.h"			// for LLOSInfo
 #include "lltimer.h"
+#include "llappcorehttp.h"
 
 class LLCommandLineParser;
 class LLFrameTimer;
 	// Metrics policy helper statics.
 	static void metricsUpdateRegion(U64 region_handle);
 	static void metricsSend(bool enable_reporting);
+
+	// llcorehttp init/shutdown/config information.
+	LLAppCoreHttp & getAppCoreHttp()			{ return mAppCoreHttp; }
 	
 protected:
 	virtual bool initWindow(); // Initialize the viewer's window.
 	
 	boost::scoped_ptr<LLUpdaterService> mUpdater;
 
+	// llcorehttp library init/shutdown helper
+	LLAppCoreHttp mAppCoreHttp;
+
 	//---------------------------------------------
 	//*NOTE: Mani - legacy updater stuff
 	// Still useable?

indra/newview/lltexturefetch.cpp

 	  mMetricsStartTime(0),
 	  mHttpHandle(LLCORE_HTTP_HANDLE_INVALID),
 	  mHttpBufferArray(NULL),
-	  mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+	  mHttpPolicyClass(mFetcher->mHttpPolicyClass),
 	  mHttpActive(false),
 	  mHttpReplySize(0U),
 	  mHttpReplyOffset(0U),
 	  mHttpOptions(NULL),
 	  mHttpHeaders(NULL),
 	  mHttpMetricsHeaders(NULL),
+	  mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
 	  mHttpSemaphore(HTTP_REQUESTS_IN_QUEUE_HIGH_WATER),
 	  mTotalCacheReadCount(0U),
 	  mTotalCacheWriteCount(0U),
 	mHttpHeaders->mHeaders.push_back("Accept: image/x-j2c");
 	mHttpMetricsHeaders = new LLCore::HttpHeaders;
 	mHttpMetricsHeaders->mHeaders.push_back("Content-Type: application/llsd+xml");
+	mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicyDefault();
 }
 
 LLTextureFetch::~LLTextureFetch()
 TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 {
 	static const U32 report_priority(1);
-	static const int report_policy_class(LLCore::HttpRequest::DEFAULT_POLICY_ID);
 	static LLCore::HttpHandler * const handler(fetcher->isQAMode() || true ? &stats_handler : NULL);
 	
 	if (! gViewerAssetStatsThread1)
 		LLCore::BufferArrayStream bas(ba);
 		LLSDSerialize::toXML(merged_llsd, bas);
 		
-		fetcher->getHttpRequest().requestPost(report_policy_class,
+		fetcher->getHttpRequest().requestPost(fetcher->getPolicyClass(),
 											  report_priority,
 											  mCapsURL,
 											  ba,
 	mTextureCache(cache),
 	mImageDecodeThread(imagedecodethread),
 	mHttpHeaders(NULL),
-	mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID)
+	mHttpPolicyClass(fetcher->getPolicyClass())
 {
 	init();
 }

indra/newview/lltexturefetch.h

 	// Threads:  T*
 	LLCore::HttpRequest & getHttpRequest()	{ return *mHttpRequest; }
 
+	// Threads:  T*
+	LLCore::HttpRequest::policy_t getPolicyClass() const { return mHttpPolicyClass; }
+	
 	// Return a pointer to the shared metrics headers definition.
 	// Does not increment the reference count, caller is required
 	// to do that to hold a reference for any length of time.
 	// Interfaces and objects into the core http library used
 	// to make our HTTP requests.  These replace the various
 	// LLCurl interfaces used in the past.
-	LLCore::HttpRequest *		mHttpRequest;							// Ttf
-	LLCore::HttpOptions *		mHttpOptions;							// Ttf
-	LLCore::HttpHeaders *		mHttpHeaders;							// Ttf
-	LLCore::HttpHeaders *		mHttpMetricsHeaders;					// Ttf
+	LLCore::HttpRequest *				mHttpRequest;					// Ttf
+	LLCore::HttpOptions *				mHttpOptions;					// Ttf
+	LLCore::HttpHeaders *				mHttpHeaders;					// Ttf
+	LLCore::HttpHeaders *				mHttpMetricsHeaders;			// Ttf
+	LLCore::HttpRequest::policy_t		mHttpPolicyClass;				// T*
 
 	// We use a resource semaphore to keep HTTP requests in
 	// WAIT_HTTP_RESOURCE2 if there aren't sufficient slots in the
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.