From fc7b5549cb6092194d11b8d87600f21992305c1c Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 31 May 2022 16:54:05 -0500
Subject: [PATCH] SL-17484 Fix for unit tests.  Deprecate non-threaded
 LLQueuedThread and make lllfsthread threaded.

---
 indra/llcommon/llqueuedthread.cpp             | 23 +++++++++-------
 indra/llcommon/lltimer.cpp                    |  7 ++++-
 indra/llfilesystem/lllfsthread.cpp            |  4 +--
 indra/llimage/llimageworker.cpp               |  8 ------
 indra/llimage/llimageworker.h                 |  3 ---
 indra/llimage/tests/llimageworker_test.cpp    | 25 ------------------
 .../tests/llcoproceduremanager_test.cpp       |  2 +-
 indra/newview/llappviewer.cpp                 | 26 +++++++++++--------
 8 files changed, 38 insertions(+), 60 deletions(-)

diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp
index 871c42f7eed..60304fff75c 100644
--- a/indra/llcommon/llqueuedthread.cpp
+++ b/indra/llcommon/llqueuedthread.cpp
@@ -37,12 +37,13 @@
 // MAIN THREAD
 LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) :
     LLThread(name),
-    mThreaded(threaded),
     mIdleThread(TRUE),
     mNextHandle(0),
     mStarted(FALSE),
+    mThreaded(threaded),
     mRequestQueue(name, 1024 * 1024)
 {
+    llassert(threaded); // not threaded implementation is deprecated
     mMainQueue = LL::WorkQueue::getInstance("mainloop");
 
 	if (mThreaded)
@@ -138,14 +139,18 @@ S32 LLQueuedThread::updateQueue(F32 max_time_ms)
 	if (mThreaded)
 	{
         // schedule a call to threadedUpdate for every call to updateQueue
-        mRequestQueue.post([=]() 
-            {
-                LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qt - update");
-                mIdleThread = FALSE;
-                threadedUpdate(); 
-                mIdleThread = TRUE;
-            }
-        );
+        if (!isQuitting())
+        {
+            mRequestQueue.post([=]()
+                {
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qt - update");
+                    mIdleThread = FALSE;
+                    threadedUpdate();
+                    mIdleThread = TRUE;
+                }
+            );
+        }
+
 		if(getPending() > 0)
 		{
 		    unpause();
diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp
index 466f98f9b2b..39dfee3755b 100644
--- a/indra/llcommon/lltimer.cpp
+++ b/indra/llcommon/lltimer.cpp
@@ -68,7 +68,12 @@ LLTimer* LLTimer::sTimer = NULL;
 void ms_sleep(U32 ms)
 {
     LL_PROFILE_ZONE_SCOPED;
-    std::this_thread::sleep_for(std::chrono::microseconds(ms));
+    using TimePoint = std::chrono::steady_clock::time_point;
+    auto resume_time = TimePoint::clock::now() + std::chrono::milliseconds(ms);
+    while (TimePoint::clock::now() < resume_time)
+    {
+        std::this_thread::yield(); //note: don't use LLThread::yield here to avoid yielding for too long
+    }
 }
 
 U32 micro_sleep(U64 us, U32 max_yields)
diff --git a/indra/llfilesystem/lllfsthread.cpp b/indra/llfilesystem/lllfsthread.cpp
index 944e981ecff..dbb69cd6055 100644
--- a/indra/llfilesystem/lllfsthread.cpp
+++ b/indra/llfilesystem/lllfsthread.cpp
@@ -45,8 +45,7 @@ void LLLFSThread::initClass(bool local_is_threaded)
 //static
 S32 LLLFSThread::updateClass(U32 ms_elapsed)
 {
-	sLocal->update((F32)ms_elapsed);
-	return sLocal->getPending();
+	return sLocal->update((F32)ms_elapsed);
 }
 
 //static
@@ -58,6 +57,7 @@ void LLLFSThread::cleanupClass()
 	{
 		sLocal->update(0);
 	}
+    sLocal->shutdown();
 	delete sLocal;
 	sLocal = NULL;
 }
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 1aace5f3e83..d8503396d78 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -68,14 +68,6 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted*
 	return handle;
 }
 
-// Used by unit test only
-// Returns the size of the mutex guarded list as an indication of sanity
-S32 LLImageDecodeThread::tut_size()
-{
-	LLMutexLock lock(mCreationMutex);
-	return 0;
-}
-
 LLImageDecodeThread::Responder::~Responder()
 {
 }
diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h
index 4619ddd6a28..e0a94d2841a 100644
--- a/indra/llimage/llimageworker.h
+++ b/indra/llimage/llimageworker.h
@@ -80,9 +80,6 @@ class LLImageDecodeThread : public LLQueuedThread
 						 Responder* responder);
 	S32 update(F32 max_time_ms);
 
-	// Used by unit tests to check the consistency of the thread instance
-	S32 tut_size();
-	
 private:
 	struct creation_info
 	{
diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp
index 462dde9fb8b..57d922b1a1b 100644
--- a/indra/llimage/tests/llimageworker_test.cpp
+++ b/indra/llimage/tests/llimageworker_test.cpp
@@ -190,35 +190,10 @@ namespace tut
 
 	template<> template<>
 	void imagedecodethread_object_t::test<1>()
-	{
-		// Test a *non threaded* instance of the class
-		mThread = new LLImageDecodeThread(false);
-		ensure("LLImageDecodeThread: non threaded constructor failed", mThread != NULL);
-		// Test that we start with an empty list right at creation
-		ensure("LLImageDecodeThread: non threaded init state incorrect", mThread->tut_size() == 0);
-		// Insert something in the queue
-		bool done = false;
-		LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, 0, FALSE, new responder_test(&done));
-		// Verifies we got a valid handle
-		ensure("LLImageDecodeThread: non threaded decodeImage(), returned handle is null", decodeHandle != 0);
-		// Verifies that we do now have something in the queued list
-		ensure("LLImageDecodeThread: non threaded decodeImage() insertion in threaded list failed", mThread->tut_size() == 1);
-		// Trigger queue handling "manually" (on a threaded instance, this is done on the thread loop)
-		S32 res = mThread->update(0);
-		// Verifies that we successfully handled the list
-		ensure("LLImageDecodeThread: non threaded update() list handling test failed", res == 0);
-		// Verifies that the list is now empty
-		ensure("LLImageDecodeThread: non threaded update() list emptying test failed", mThread->tut_size() == 0);
-	}
-
-	template<> template<>
-	void imagedecodethread_object_t::test<2>()
 	{
 		// Test a *threaded* instance of the class
 		mThread = new LLImageDecodeThread(true);
 		ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL);
-		// Test that we start with an empty list right at creation
-		ensure("LLImageDecodeThread: threaded init state incorrect", mThread->tut_size() == 0);
 		// Insert something in the queue
 		bool done = false;
 		LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, 0, FALSE, new responder_test(&done));
diff --git a/indra/llmessage/tests/llcoproceduremanager_test.cpp b/indra/llmessage/tests/llcoproceduremanager_test.cpp
index 6424117ef32..78424a28c8f 100644
--- a/indra/llmessage/tests/llcoproceduremanager_test.cpp
+++ b/indra/llmessage/tests/llcoproceduremanager_test.cpp
@@ -48,7 +48,7 @@
 #pragma warning(disable: 4702)
 #endif
 
-LLCoreHttpUtil::HttpCoroutineAdapter::HttpCoroutineAdapter(std::string const&, unsigned int, unsigned int)
+LLCoreHttpUtil::HttpCoroutineAdapter::HttpCoroutineAdapter(std::string const&, unsigned int)
 {
 }
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index a172308d2aa..d7ed2bb4df2 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1680,16 +1680,20 @@ S32 LLAppViewer::updateTextureThreads(F32 max_time)
 
 void LLAppViewer::flushLFSIO()
 {
-	while (1)
-	{
-		S32 pending = LLLFSThread::updateClass(0);
-		if (!pending)
-		{
-			break;
-		}
-		LL_INFOS() << "Waiting for pending IO to finish: " << pending << LL_ENDL;
-		ms_sleep(100);
-	}
+    S32 pending = LLLFSThread::updateClass(0);
+    if (pending > 0)
+    {
+        LL_INFOS() << "Waiting for pending IO to finish: " << pending << LL_ENDL;
+        while (1)
+        {
+            pending = LLLFSThread::updateClass(0);
+            if (!pending)
+            {
+                break;
+            }
+            ms_sleep(100);
+        }
+    }
 }
 
 bool LLAppViewer::cleanup()
@@ -2187,7 +2191,7 @@ bool LLAppViewer::initThreads()
 
 	LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange"));
 
-	LLLFSThread::initClass(enable_threads && false);
+	LLLFSThread::initClass(enable_threads && true); // TODO: fix crashes associated with this shutdo
 
 	// Image decoding
 	LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
-- 
GitLab