From d7f555b3afb9ca624f7a561b64a3454837689dee Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@bred.dog>
Date: Tue, 27 Aug 2019 19:05:09 -0400
Subject: [PATCH] Merges make me scream. Unbreak thread and mutex(ITS STILL
 SHIT) Fix build. Fix more of the build. Fix crash at start.

---
 indra/llcommon/llapr.cpp                      |  2 +-
 indra/llcommon/llapr.h                        |  2 +-
 indra/llcommon/llerror.cpp                    | 32 +++---
 indra/llcommon/llmutex.cpp                    | 38 +------
 indra/llcommon/llmutex.h                      |  6 +-
 indra/llcommon/llthread.cpp                   | 98 +++++++------------
 indra/llcommon/llthread.h                     | 12 ++-
 indra/llmessage/llpumpio.cpp                  |  6 +-
 indra/llprimitive/llmodelloader.cpp           |  2 +-
 indra/llrender/llglslshader.h                 |  2 +-
 indra/llui/llrngwriter.cpp                    | 31 +++---
 indra/llui/llxuiparser.cpp                    | 29 +++---
 indra/llxml/llcontrol.cpp                     |  2 +-
 indra/llxml/llcontrol.h                       |  2 +-
 .../newview/llfloaterconversationpreview.cpp  |  1 -
 indra/newview/llfloatertopobjects.cpp         |  1 +
 indra/newview/lllogchat.cpp                   |  9 +-
 indra/newview/lllogchat.h                     |  2 +-
 indra/newview/llmeshrepository.cpp            | 16 +--
 indra/newview/llpanelpeople.cpp               |  8 +-
 indra/newview/llpanelpeople.h                 |  1 +
 indra/newview/lltexturecache.cpp              |  8 +-
 .../skins/default/xui/en/notifications.xml    | 15 +++
 .../skins/default/xui/en/panel_people.xml     |  3 +
 24 files changed, 151 insertions(+), 177 deletions(-)

diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 3b6cb53fa7..e0a951f4ed 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -147,7 +147,7 @@ LLVolatileAPRPool::LLVolatileAPRPool(const std::string& name, BOOL is_local, apr
 	//create mutex
 	if(!is_local) //not a local apr_pool, that is: shared by multiple threads.
 	{
-		mMutexp.reset(new std::mutex());
+		mMutexp = std::make_unique<LLMutex>();
 	}
 }
 
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 559f8b8ee2..3ce8588f9e 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -126,7 +126,7 @@ private:
 	S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
 	S32 mNumTotalRef ;  //number of total pointers pointing to the apr_pool since last creating.  
 
-	std::unique_ptr<std::mutex> mMutexp;
+	std::unique_ptr<LLMutex> mMutexp;
 } ;
 // File IO convenience functions.
 // Returns NULL if the file fails to open, sets *sizep to file size if not NULL
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 10bc6018a5..b49a720587 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -1147,8 +1147,8 @@ namespace
 }
 
 namespace {
-	LLMutex gLogMutex;
-	LLMutex gCallStacksLogMutex;
+	std::unique_ptr<LLMutex> gLogMutexp;
+	std::unique_ptr<LLMutex> gCallStacksLogMutexp;
 
 	bool checkLevelMap(const LevelMap& map, const std::string& key,
 						LLError::ELevel& level)
@@ -1195,7 +1195,8 @@ namespace LLError
 
 	bool Log::shouldLog(CallSite& site)
 	{
-		LLMutexTrylock lock(&gLogMutex, 5);
+		if (!gLogMutexp) gLogMutexp = std::make_unique<LLMutex>();
+		LLMutexTrylock lock(gLogMutexp.get(), 5);
 		if (!lock.isLocked())
 		{
 			return false;
@@ -1246,7 +1247,8 @@ namespace LLError
 
 	std::ostringstream* Log::out()
 	{
-		LLMutexTrylock lock(&gLogMutex,5);
+		if (!gLogMutexp) gLogMutexp = std::make_unique<LLMutex>();
+		LLMutexTrylock lock(gLogMutexp.get(), 5);
 		// If we hit a logging request very late during shutdown processing,
 		// when either of the relevant LLSingletons has already been deleted,
 		// DO NOT resurrect them.
@@ -1266,7 +1268,8 @@ namespace LLError
 
 	void Log::flush(std::ostringstream* out, char* message)
 	{
-		LLMutexTrylock lock(&gLogMutex,5);
+		if (!gLogMutexp) gLogMutexp = std::make_unique<LLMutex>();
+		LLMutexTrylock lock(gLogMutexp.get(), 5);
 		if (!lock.isLocked())
 		{
 			return;
@@ -1306,7 +1309,8 @@ namespace LLError
 
 	void Log::flush(std::ostringstream* out, const CallSite& site)
 	{
-		LLMutexTrylock lock(&gLogMutex,5);
+		if (!gLogMutexp) gLogMutexp = std::make_unique<LLMutex>();
+		LLMutexTrylock lock(gLogMutexp.get(), 5);
 		if (!lock.isLocked())
 		{
 			return;
@@ -1476,9 +1480,6 @@ namespace LLError
 		return chars ? time_str : "time error";
 	}
 }
-#if !SINGLE_THREADED
-std::unique_ptr<LLMutex> gCallStacksLogMutexp;
-#endif
 
 namespace LLError
 {     
@@ -1513,7 +1514,9 @@ namespace LLError
    //static
    void LLCallStacks::push(const char* function, const int line)
    {
-       LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+	   if (!gCallStacksLogMutexp) gCallStacksLogMutexp = std::make_unique<LLMutex>();
+	   LLMutexTrylock lock(gCallStacksLogMutexp.get(), 5);
+
        if (!lock.isLocked())
        {
            return;
@@ -1548,7 +1551,8 @@ namespace LLError
    //static
    void LLCallStacks::end(std::ostringstream* _out)
    {
-       LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+	   if (!gCallStacksLogMutexp) gCallStacksLogMutexp = std::make_unique<LLMutex>();
+	   LLMutexTrylock lock(gCallStacksLogMutexp.get(), 5);
        if (!lock.isLocked())
        {
            return;
@@ -1570,7 +1574,8 @@ namespace LLError
    //static
    void LLCallStacks::print()
    {
-       LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+	   if (!gCallStacksLogMutexp) gCallStacksLogMutexp = std::make_unique<LLMutex>();
+	   LLMutexTrylock lock(gCallStacksLogMutexp.get(), 5);
        if (!lock.isLocked())
        {
            return;
@@ -1608,7 +1613,8 @@ namespace LLError
 
 bool debugLoggingEnabled(const std::string& tag)
 {
-    LLMutexTrylock lock(&gLogMutex, 5);
+	if (!gLogMutexp) gLogMutexp = std::make_unique<LLMutex>();
+    LLMutexTrylock lock(gLogMutexp.get(), 5);
     if (!lock.isLocked())
     {
         return false;
diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp
index a434ad3f32..5603d48235 100644
--- a/indra/llcommon/llmutex.cpp
+++ b/indra/llcommon/llmutex.cpp
@@ -32,7 +32,7 @@
 
 LLMutex::LLMutex() :
  mCount(0),
- mLockingThread(NO_THREAD)
+ mLockingThread()
 {
 }
 
@@ -79,7 +79,7 @@ void LLMutex::unlock()
 	mIsLocked[id] = FALSE;
 #endif
 
-	mLockingThread = NO_THREAD;
+	mLockingThread = std::thread::id();
 	mMutex.unlock();
 }
 
@@ -101,7 +101,7 @@ bool LLMutex::isSelfLocked()
 	return mLockingThread == LLThread::currentID();
 }
 
-U32 LLMutex::lockingThread() const
+std::thread::id LLMutex::lockingThread() const
 {
 	return mLockingThread;
 }
@@ -192,36 +192,4 @@ LLMutexTrylock::~LLMutexTrylock()
         mMutex->unlock();
 }
 
-
-//---------------------------------------------------------------------
-//
-// LLScopedLock
-//
-LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex)
-{
-	if(mutex)
-	{
-		mutex->lock();
-		mLocked = true;
-	}
-	else
-	{
-		mLocked = false;
-	}
-}
-
-LLScopedLock::~LLScopedLock()
-{
-	unlock();
-}
-
-void LLScopedLock::unlock()
-{
-	if(mLocked)
-	{
-		mMutex->unlock();
-		mLocked = false;
-	}
-}
-
 //============================================================================
diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h
index 9d7b3bdcc1..2f06aec0ee 100644
--- a/indra/llcommon/llmutex.h
+++ b/indra/llcommon/llmutex.h
@@ -66,12 +66,12 @@ public:
 	void unlock();		// undefined behavior when called on mutex not being held
 	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
+	std::thread::id lockingThread() const; //get ID of locking thread
 	
 protected:
 	std::mutex			mMutex;
 	mutable U32			mCount;
-	mutable U32			mLockingThread;
+	mutable std::thread::id			mLockingThread;
 	
 #if MUTEX_DEBUG
 	std::map<U32, BOOL> mIsLocked;
@@ -115,7 +115,7 @@ private:
 //============================================================================
 
 // Scoped locking class similar in function to LLMutexLock but uses
-// the try_lock() method to conditionally acquire lock without
+// the trylock() method to conditionally acquire lock without
 // blocking.  Caller resolves the resulting condition by calling
 // the isLocked() method and either punts or continues as indicated.
 //
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 17c2130200..1c43a5fc12 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -38,8 +38,7 @@
 
 
 #ifdef LL_WINDOWS
-const DWORD MS_VC_EXCEPTION=0x406D1388;
-
+const DWORD MS_VC_EXCEPTION = 0x406D1388;
 #pragma pack(push,8)
 typedef struct tagTHREADNAME_INFO
 {
@@ -91,7 +90,7 @@ void set_thread_name( DWORD dwThreadID, const char* threadName)
 
 LL_COMMON_API void assert_main_thread()
 {
-	static boost::thread::id s_thread_id = LLThread::currentID();
+	static std::thread::id s_thread_id = LLThread::currentID();
 	if (LLThread::currentID() != s_thread_id)
 	{
 		LL_WARNS() << "Illegal execution from thread id " << LLThread::currentID()
@@ -139,11 +138,13 @@ void LLThread::threadRun()
 
     // We're done with the run function, this thread is done executing now.
     //NB: we are using this flag to sync across threads...we really need memory barriers here
+    // Todo: add LLMutex per thread instead of flag?
+    // We are using "while (mStatus != STOPPED) {ms_sleep();}" everywhere.
     mStatus = STOPPED;
 }
 
 LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
-    mPaused(FALSE),
+    mPaused(false),
     mName(name),
 	mRunCondition(std::make_unique<LLCondition>()),
 	mDataLock(std::make_unique<LLMutex>()),
@@ -195,6 +196,8 @@ void LLThread::shutdown()
 			{
 				break;
 			}
+            // Sleep for a tenth of a second
+            std::this_thread::sleep_for(std::chrono::milliseconds(100));
 			yield();
 		}
 
@@ -204,50 +207,21 @@ void LLThread::shutdown()
 		}
 	}
 
-	if (mThread.joinable())
-	{
-		try
-		{
-			bool joined = false;
-			constexpr U32 MAX_WAIT = 100;
-			for(U32 count = 0; count < MAX_WAIT; count++)
-			{
-				// Try to join for a tenth of a second
-				if (mThread.try_join_for(boost::chrono::milliseconds(100)))
-				{
-					LL_INFOS() << "Successfully joined thread: \"" << mName << "\"" << LL_ENDL;
-					joined = true;
-					break;
-				}
-				yield();
-			}
-
-			if (!joined)
-			{
-				// This thread just wouldn't join, even though we gave it time
-				LL_WARNS() << "Forcefully terminating thread: \"" << mName << "\" with id: " << mThread.get_id() << " before clean exit!" << LL_ENDL;
-				// Put a stake in its heart.
-				boost::thread::native_handle_type thread(mThread.native_handle());
-#if LL_WINDOWS
-				TerminateThread(thread, 0);
+    if (!isStopped())
+    {
+		LL_WARNS("THREAD") << "Forced to terminated thread: " << mName << LL_ENDL;
+        // This thread just wouldn't stop, even though we gave it time
+        //LL_WARNS() << "LLThread::~LLThread() exiting thread before clean exit!" << LL_ENDL;
+        // Put a stake in its heart. (A very hostile method to force a thread to quit)
+#if	LL_WINDOWS
+		TerminateThread(mNativeHandle, 0);
 #else
-				pthread_cancel(thread);
+		pthread_cancel(mNativeHandle);
 #endif
-			}
-		}
-		catch (const boost::thread_interrupted&)
-		{
-			LL_WARNS() << "Failed to join thread: \"" << mName << "\" with id: " << mThread.get_id() << " and interrupted exception" << LL_ENDL;
-		}
+		mStatus = CRASHED;
 	}
 
-	mRecorder.reset();
-
-	if (mIsLocalPool && mAPRPoolp)
-	{
-		apr_pool_destroy(mAPRPoolp);
-		mAPRPoolp = nullptr;
-	}
+	mRecorder.reset(nullptr);
 }
 
 
@@ -258,17 +232,17 @@ void LLThread::start()
     // Set thread state to running
     mStatus = RUNNING;
 
-    try
-    {
-        mThreadp = new std::thread(std::bind(&LLThread::threadRun, this));
-        mNativeHandle = mThreadp->native_handle();
-    }
-    catch (const std::system_error& ex)
-    {
-        mStatus = CRASHED;
-        LL_WARNS() << "failed to start thread " << mName << " " << ex.what() << LL_ENDL;
-    }
-
+	try
+	{
+		mThread = std::thread::thread(std::bind(&LLThread::threadRun, this));
+		mNativeHandle = mThread.native_handle();
+		mThread.detach();
+	}
+	catch (const std::system_error& err)
+	{
+		mStatus = CRASHED;
+		LL_WARNS() << "Failed to start thread: \"" << mName << "\" due to error: " << err.what() << LL_ENDL;
+	}
 }
 
 //============================================================================
@@ -281,7 +255,7 @@ void LLThread::pause()
     if (!mPaused)
     {
         // this will cause the thread to stop execution as soon as checkPause() is called
-        mPaused = 1;        // Does not need to be atomic since this is only set/unset from the main thread
+        mPaused = true;        // Does not need to be atomic since this is only set/unset from the main thread
     }   
 }
 
@@ -289,7 +263,7 @@ void LLThread::unpause()
 {
     if (mPaused)
     {
-        mPaused = 0;
+        mPaused = false;
     }
 
     wake(); // wake up the thread if necessary
@@ -335,15 +309,15 @@ void LLThread::setQuitting()
 }
 
 // static
-boost::thread::id LLThread::currentID()
+std::thread::id LLThread::currentID()
 {
-	return boost::this_thread::get_id();
+	return std::this_thread::get_id();
 }
 
 // static
 void LLThread::yield()
 {
-    apr_thread_yield();
+    std::this_thread::yield();
 }
 
 void LLThread::wake()
@@ -395,9 +369,9 @@ LLThreadSafeRefCount::LLThreadSafeRefCount() :
 {
 }
 
-LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src)
+LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src) :
+	mRef(0)
 {
-    mRef = 0;
 }
 
 LLThreadSafeRefCount::~LLThreadSafeRefCount()
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index 2e52e3497a..b7da25a16a 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -62,7 +62,7 @@ public:
     bool isStopped() const { return (STOPPED == mStatus) || (CRASHED == mStatus); }
     bool isCrashed() const { return (CRASHED == mStatus); } 
     
-    static boost::thread::id currentID(); // Return ID of current thread
+    static std::thread::id currentID(); // Return ID of current thread
     static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure.
     
 public:
@@ -86,20 +86,22 @@ public:
 
     LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
 
+    std::thread::id getID() const { return mID; }
 private:
     bool                mPaused;
     std::thread::native_handle_type mNativeHandle; // for termination in case of issues
     
-    // static function passed to APR thread creation routine
-    void threadRun();
+    // function passed to std::thread creation routine
+	void threadRun();
 
 protected:
-    std::string         mName;
+	std::string						mName;
 	std::unique_ptr<LLCondition>	mRunCondition;
 	std::unique_ptr<LLMutex>		mDataLock;
 
-    std::thread        *mThreadp;
+	std::thread        mThread;
     EThreadStatus       mStatus;
+    std::thread::id                 mID;
 	std::unique_ptr<LLTrace::ThreadRecorder> mRecorder;
 
     //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp
index 5200f756f9..7e9ff5d2e9 100644
--- a/indra/llmessage/llpumpio.cpp
+++ b/indra/llmessage/llpumpio.cpp
@@ -159,9 +159,9 @@ LLPumpIO::LLPumpIO(apr_pool_t* pool) :
 	mPollsetClientID(0),
 	mNextLock(0),
 	mCurrentChain(mRunningChains.end()),
-	mPool(NULL),
-	mCurrentPool(NULL),
-	mCurrentPoolReallocCount(0),
+	mPool(nullptr),
+	mCurrentPool(nullptr),
+	mCurrentPoolReallocCount(0)
 {
 	mCurrentChain = mRunningChains.end();
 
diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp
index 31a38799cb..504112c451 100644
--- a/indra/llprimitive/llmodelloader.cpp
+++ b/indra/llprimitive/llmodelloader.cpp
@@ -367,7 +367,7 @@ void LLModelLoader::loadModelCallback()
 
 	while (!isStopped())
 	{ //wait until this thread is stopped before deleting self
-		boost::this_thread::sleep_for(boost::chrono::microseconds(100));
+		std::this_thread::sleep_for(std::chrono::microseconds(100));
 	}
 
 	//double check if "this" is valid before deleting it, in case it is aborted during running.
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 4f932d3f16..3db1bce4ba 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -157,7 +157,7 @@ public:
 		{
 			if (uniform >= 0)
 			{
-				typename std::vector<std::pair<GLint, T> >::iterator iter = std::find_if(cache.begin(), cache.end(), boost::bind(&std::pair<GLint, T>::first, _1) == uniform);
+				typename std::vector<std::pair<GLint, T> >::iterator iter = std::find_if(cache.begin(), cache.end(), [&](const auto& pair) { return pair.first == uniform; });
 				if (iter == cache.cend())
 				{
 					T tmp;
diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp
index bbaac8b9d2..3694e10c4a 100644
--- a/indra/llui/llrngwriter.cpp
+++ b/indra/llui/llrngwriter.cpp
@@ -38,6 +38,8 @@
 #include "lluictrlfactory.h"
 #endif
 
+#include <functional>
+
 static 	LLInitParam::Parser::parser_read_func_map_t sReadFuncs;
 static 	LLInitParam::Parser::parser_write_func_map_t sWriteFuncs;
 static 	LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs;
@@ -48,21 +50,22 @@ static 	LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs;
 LLRNGWriter::LLRNGWriter()
 : Parser(sReadFuncs, sWriteFuncs, sInspectFuncs)
 {
+	using namespace std::placeholders;
 	// register various callbacks for inspecting the contents of a param block
-	registerInspectFunc<bool>(boost::bind(&LLRNGWriter::writeAttribute, this, "boolean", _1, _2, _3, _4));
-	registerInspectFunc<std::string>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
-	registerInspectFunc<U8>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedByte", _1, _2, _3, _4));
-	registerInspectFunc<S8>(boost::bind(&LLRNGWriter::writeAttribute, this, "signedByte", _1, _2, _3, _4));
-	registerInspectFunc<U16>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedShort", _1, _2, _3, _4));
-	registerInspectFunc<S16>(boost::bind(&LLRNGWriter::writeAttribute, this, "signedShort", _1, _2, _3, _4));
-	registerInspectFunc<U32>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedInt", _1, _2, _3, _4));
-	registerInspectFunc<S32>(boost::bind(&LLRNGWriter::writeAttribute, this, "integer", _1, _2, _3, _4));
-	registerInspectFunc<F32>(boost::bind(&LLRNGWriter::writeAttribute, this, "float", _1, _2, _3, _4));
-	registerInspectFunc<F64>(boost::bind(&LLRNGWriter::writeAttribute, this, "double", _1, _2, _3, _4));
-	registerInspectFunc<LLColor4>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
-	registerInspectFunc<LLUIColor>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
-	registerInspectFunc<LLUUID>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
-	registerInspectFunc<LLSD>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
+	registerInspectFunc<bool>(std::bind(&LLRNGWriter::writeAttribute, this, "boolean", _1, _2, _3, _4));
+	registerInspectFunc<std::string>(std::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
+	registerInspectFunc<U8>(std::bind(&LLRNGWriter::writeAttribute, this, "unsignedByte", _1, _2, _3, _4));
+	registerInspectFunc<S8>(std::bind(&LLRNGWriter::writeAttribute, this, "signedByte", _1, _2, _3, _4));
+	registerInspectFunc<U16>(std::bind(&LLRNGWriter::writeAttribute, this, "unsignedShort", _1, _2, _3, _4));
+	registerInspectFunc<S16>(std::bind(&LLRNGWriter::writeAttribute, this, "signedShort", _1, _2, _3, _4));
+	registerInspectFunc<U32>(std::bind(&LLRNGWriter::writeAttribute, this, "unsignedInt", _1, _2, _3, _4));
+	registerInspectFunc<S32>(std::bind(&LLRNGWriter::writeAttribute, this, "integer", _1, _2, _3, _4));
+	registerInspectFunc<F32>(std::bind(&LLRNGWriter::writeAttribute, this, "float", _1, _2, _3, _4));
+	registerInspectFunc<F64>(std::bind(&LLRNGWriter::writeAttribute, this, "double", _1, _2, _3, _4));
+	registerInspectFunc<LLColor4>(std::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
+	registerInspectFunc<LLUIColor>(std::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
+	registerInspectFunc<LLUUID>(std::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
+	registerInspectFunc<LLSD>(std::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4));
 }
 
 void LLRNGWriter::writeRNG(const std::string& type_name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace)
diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp
index 8fd0df003b..ebbd908c5d 100644
--- a/indra/llui/llxuiparser.cpp
+++ b/indra/llui/llxuiparser.cpp
@@ -315,20 +315,21 @@ public:
 LLXSDWriter::LLXSDWriter()
 : Parser(sXSDReadFuncs, sXSDWriteFuncs, sXSDInspectFuncs)
 {
-	registerInspectFunc<bool>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:boolean", _1, _2, _3, _4));
-	registerInspectFunc<std::string>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
-	registerInspectFunc<U8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedByte", _1, _2, _3, _4));
-	registerInspectFunc<S8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedByte", _1, _2, _3, _4));
-	registerInspectFunc<U16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedShort", _1, _2, _3, _4));
-	registerInspectFunc<S16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedShort", _1, _2, _3, _4));
-	registerInspectFunc<U32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedInt", _1, _2, _3, _4));
-	registerInspectFunc<S32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:integer", _1, _2, _3, _4));
-	registerInspectFunc<F32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:float", _1, _2, _3, _4));
-	registerInspectFunc<F64>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:double", _1, _2, _3, _4));
-	registerInspectFunc<LLColor4>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
-	registerInspectFunc<LLUIColor>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
-	registerInspectFunc<LLUUID>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
-	registerInspectFunc<LLSD>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
+	using namespace std::placeholders;
+	registerInspectFunc<bool>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:boolean", _1, _2, _3, _4));
+	registerInspectFunc<std::string>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
+	registerInspectFunc<U8>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedByte", _1, _2, _3, _4));
+	registerInspectFunc<S8>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:signedByte", _1, _2, _3, _4));
+	registerInspectFunc<U16>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedShort", _1, _2, _3, _4));
+	registerInspectFunc<S16>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:signedShort", _1, _2, _3, _4));
+	registerInspectFunc<U32>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedInt", _1, _2, _3, _4));
+	registerInspectFunc<S32>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:integer", _1, _2, _3, _4));
+	registerInspectFunc<F32>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:float", _1, _2, _3, _4));
+	registerInspectFunc<F64>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:double", _1, _2, _3, _4));
+	registerInspectFunc<LLColor4>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
+	registerInspectFunc<LLUIColor>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
+	registerInspectFunc<LLUUID>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
+	registerInspectFunc<LLSD>(std::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4));
 }
 
 LLXSDWriter::~LLXSDWriter() {}
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index 22cf9b20c7..2d1c6b2391 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -558,7 +558,7 @@ LLControlVariable* LLControlGroup::declareLLSD(const std::string& name, const LL
 	return declareControl(name, TYPE_LLSD, initial_val, comment, persist);
 }
 
-void LLControlGroup::incrCount(const std::string& name)
+void LLControlGroup::incrCount(const std::string& name) const
 {
 	if (0.0 == start_time)
 	{
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index ec7e1fb440..d244a022c5 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -276,7 +276,7 @@ public:
  	U32 saveToFile(const std::string& filename, BOOL nondefault_only);
  	U32	loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true);
 	void	resetToDefaults();
-	void	incrCount(const std::string& name);
+	void	incrCount(const std::string& name) const;
 
 	bool	mSettingsProfile;
 };
diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp
index c1cc1c225e..9ce98ca9d2 100644
--- a/indra/newview/llfloaterconversationpreview.cpp
+++ b/indra/newview/llfloaterconversationpreview.cpp
@@ -49,7 +49,6 @@ LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_i
 	mMessages(nullptr),
 	mAccountName(session_id[LL_FCP_ACCOUNT_NAME]),
 	mCompleteName(session_id[LL_FCP_COMPLETE_NAME]),
-	mMutex(NULL),
 	mShowHistory(false),
 	mHistoryThreadsBusy(false),
 	mOpened(false)
diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp
index c94cd8877e..d69662336a 100644
--- a/indra/newview/llfloatertopobjects.cpp
+++ b/indra/newview/llfloatertopobjects.cpp
@@ -122,6 +122,7 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
 {
     U32 request_flags;
 	U32 total_count;
+	U64 total_memory = 0;
 
 	msg->getU32Fast(_PREHASH_RequestData, _PREHASH_RequestFlags, request_flags);
 	msg->getU32Fast(_PREHASH_RequestData, _PREHASH_TotalObjectCount, total_count);
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index df45eec905..084a1c3c14 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -562,11 +562,8 @@ void LLLogChat::findTranscriptFiles(const std::string& pattern, std::vector<std:
 	{
 		std::string fullname = gDirUtilp->add(dirname, filename);
 		if (isTranscriptFileFound(fullname))
-		if (NULL != filep)
 		{
 			list_of_transcriptions.push_back(fullname);
-			S32 bytes_to_read = ftell(filep);	// get current file pointer
-			if (bytes_to_read > 0 && NULL != fgets(buffer, bytes_to_read, filep))
 		}		
 	}
 }
@@ -740,13 +737,13 @@ bool LLLogChat::isNearbyTranscriptExist()
 	return isTranscriptFileFound(makeLogFileName("chat"));;
 }
 
-bool LLLogChat::isAdHocTranscriptExist(std::string file_name)
+bool LLLogChat::isAdHocTranscriptExist(const std::string& file_name)
 {
-	return isTranscriptFileFound(makeLogFileName(file_name));;
+	return isTranscriptFileFound(makeLogFileName(file_name));
 }
 
 // static
-bool LLLogChat::isTranscriptFileFound(std::string fullname)
+bool LLLogChat::isTranscriptFileFound(const std::string& fullname)
 {
 	bool result = false;
 	LLFILE * filep = LLFile::fopen(fullname, "rb");
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index 401250beb8..380fbf1a4e 100644
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -121,7 +121,7 @@ public:
 	static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false);
 	static bool isNearbyTranscriptExist();
 	static bool isAdHocTranscriptExist(const std::string& file_name);
-	static bool isTranscriptFileFound(std::string fullname);
+	static bool isTranscriptFileFound(const std::string& fullname);
 
 	static bool historyThreadsFinished(LLUUID session_id);
 	static LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id);
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 957585c007..61ef901351 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -2592,7 +2592,7 @@ void LLMeshUploadThread::generateHulls()
 		// on isDiscarded() prevents that.
 		while (! mPhysicsComplete && ! isDiscarded())
 		{
-			boost::this_thread::sleep_for(boost::chrono::microseconds(100));
+			std::this_thread::sleep_for(std::chrono::microseconds(100));
 		}
 	}	
 }
@@ -2890,7 +2890,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()
 
 	if (!mSkinInfoQ.empty())
 	{
-		if (mMutex->try_lock())
+		if (mMutex->trylock())
 		{
 			std::queue<LLMeshSkinInfo> skin_info_q;
 			if (! mSkinInfoQ.empty())
@@ -2910,7 +2910,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()
 
 	if (!mSkinUnavailableQ.empty())
 	{
-		if (mMutex->try_lock())
+		if (mMutex->trylock())
 		{
 			std::queue<UUIDBasedRequest> skin_info_unavail_q;
 			if (!mSkinUnavailableQ.empty())
@@ -2930,7 +2930,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()
 
 	if (!mDecompositionQ.empty())
 	{
-		if (mMutex->try_lock())
+		if (mMutex->trylock())
 		{
 			std::list<LLModel::Decomposition*> decomp_q;
 			if (! mDecompositionQ.empty())
@@ -3526,7 +3526,7 @@ void LLMeshRepository::init()
 
 	while (!mDecompThread->mInited)
 	{ //wait for physics decomp thread to init
-		boost::this_thread::sleep_for(boost::chrono::microseconds(100));
+		std::this_thread::sleep_for(std::chrono::microseconds(100));
 	}
 
 	metrics_teleport_started_signal = LLViewerMessage::getInstance()->setTeleportStartedCallback(teleport_started);
@@ -3553,7 +3553,7 @@ void LLMeshRepository::shutdown()
 	
 	while (!mThread->isStopped())
 	{
-		boost::this_thread::sleep_for(boost::chrono::microseconds(10));
+		std::this_thread::sleep_for(std::chrono::microseconds(10));
 	}
 	delete mThread;
 	mThread = nullptr;
@@ -3563,7 +3563,7 @@ void LLMeshRepository::shutdown()
 		LL_INFOS(LOG_MESH) << "Waiting for pending mesh upload " << (i + 1) << "/" << mUploads.size() << LL_ENDL;
 		while (!mUploads[i]->isStopped())
 		{
-			boost::this_thread::sleep_for(boost::chrono::microseconds(10));
+			std::this_thread::sleep_for(std::chrono::microseconds(10));
 		}
 		delete mUploads[i];
 	}
@@ -4755,7 +4755,7 @@ void LLPhysicsDecomp::shutdown()
 
 		while (!isStopped())
 		{
-			boost::this_thread::sleep_for(boost::chrono::microseconds(10));
+			std::this_thread::sleep_for(std::chrono::microseconds(10));
 		}
 	}
 }
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index c192dc4797..cb276747c8 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -82,6 +82,8 @@ static const std::string RECENT_TAB_NAME	= "recent_panel";
 static const std::string BLOCKED_TAB_NAME	= "blocked_panel"; // blocked avatars
 static const std::string COLLAPSED_BY_USER  = "collapsed_by_user";
 
+const S32 BASE_MAX_AGENT_GROUPS = 42;
+const S32 PREMIUM_MAX_AGENT_GROUPS = 60;
 
 extern S32 gMaxAgentGroups;
 
@@ -969,8 +971,10 @@ void LLPanelPeople::updateButtons()
 		}
 
 		mGroupMinusBtn->setEnabled(item_selected && selected_id.notNull()); // a real group selected
-		mGroupCountText->setTextArg("[COUNT]", std::to_string(gAgent.mGroups.size()));
-		mGroupCountText->setTextArg("[REMAINING]", std::to_string(gMaxAgentGroups-gAgent.mGroups.size()));
+		U32 groups_count = gAgent.mGroups.size();
+		U32 groups_ramaining = gMaxAgentGroups > groups_count ? gMaxAgentGroups - groups_count : 0;
+		mGroupCountText->setTextArg("[COUNT]", std::to_string(groups_count));
+		mGroupCountText->setTextArg("[REMAINING]", std::to_string(groups_ramaining));
 	}
 	else
 	{
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index 8037e16d4f..07e4998f3d 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -101,6 +101,7 @@ private:
 
 	// UI callbacks
 	void					onFilterEdit(const std::string& search_string);
+	void					onGroupLimitInfo();
 	void					onTabSelected(const LLSD& param);
 	void					onAddFriendButtonClicked();
 	void					onAddFriendWizButtonClicked();
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 472b2841f9..96d9cb2ac4 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -1037,12 +1037,12 @@ U64 LLTextureCache::initCache(ELLPath location, U64 max_size, BOOL texture_cache
 	llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized.
 
 	U64 entries_size = (max_size * 36) / 100; //0.36 * max_size
-	U32 max_entries = header_size / (TEXTURE_CACHE_ENTRY_SIZE + TEXTURE_FAST_CACHE_ENTRY_SIZE);
+	U32 max_entries = entries_size / (TEXTURE_CACHE_ENTRY_SIZE + TEXTURE_FAST_CACHE_ENTRY_SIZE);
 	sCacheMaxEntries = (llmin(sCacheMaxEntries, max_entries));
-	header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE;
-	max_size -= header_size;
+	entries_size = sCacheMaxEntries * (TEXTURE_CACHE_ENTRY_SIZE + TEXTURE_FAST_CACHE_ENTRY_SIZE);
+	max_size -= entries_size;
 	if (sCacheMaxTexturesSize > 0)
-		sCacheMaxTexturesSize = (U32)llmin((U64)sCacheMaxTexturesSize, max_size);
+		sCacheMaxTexturesSize = (S64)llmin((U64)sCacheMaxTexturesSize, max_size);
 	else
 		sCacheMaxTexturesSize = max_size;
 	max_size -= sCacheMaxTexturesSize;
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 22d3e983a1..edde504596 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -4298,6 +4298,21 @@ You have reached your maximum number of groups. Please leave some group before j
      yestext="OK"/>
   </notification>
 
+  <notification
+   icon="alert.tga"
+   name="GroupLimitInfo"
+   type="alert">
+The group limit for base accounts is [MAX_BASIC], and for [https://secondlife.com/premium/ premium]
+accounts is [MAX_PREMIUM].
+If you downgraded your account, you will need to get below [MAX_BASIC] group limit before you can join more.
+
+[https://secondlife.com/my/account/membership.php Upgrade today!]
+    <tag>group</tag>
+    <usetemplate
+     name="okbutton"
+     yestext="Close"/>
+  </notification>
+
   <notification
    icon="alert.tga"
    name="KickUser"
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 0b45f758ae..4970c59e58 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -54,6 +54,9 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
 	<string
 	 name="AltMiniMapToolTipMsg"
 	 value="[REGION](Double-click to teleport, shift-drag to pan)"/>
+	<string
+	 name="GroupCountWithInfo"
+	 value="You belong to [COUNT] groups, and can join [REMAINING] more.  [secondlife:/// Want more?]"/>
     <tab_container
      bottom="-5"
      follows="all"
-- 
GitLab