summaryrefslogtreecommitdiff
path: root/indra/llcommon/llthread.cpp
diff options
context:
space:
mode:
authorAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
committerAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
commit1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch)
treeab243607f74f78200787bba5b9b88f07ef1b966f /indra/llcommon/llthread.cpp
parent6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff)
parente1623bb276f83a43ce7a197e388720c05bdefe61 (diff)
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts: # autobuild.xml # indra/cmake/CMakeLists.txt # indra/cmake/GoogleMock.cmake # indra/llaudio/llaudioengine_fmodstudio.cpp # indra/llaudio/llaudioengine_fmodstudio.h # indra/llaudio/lllistener_fmodstudio.cpp # indra/llaudio/lllistener_fmodstudio.h # indra/llaudio/llstreamingaudio_fmodstudio.cpp # indra/llaudio/llstreamingaudio_fmodstudio.h # indra/llcharacter/llmultigesture.cpp # indra/llcharacter/llmultigesture.h # indra/llimage/llimage.cpp # indra/llimage/llimagepng.cpp # indra/llimage/llimageworker.cpp # indra/llimage/tests/llimageworker_test.cpp # indra/llmessage/tests/llmockhttpclient.h # indra/llprimitive/llgltfmaterial.h # indra/llrender/llfontfreetype.cpp # indra/llui/llcombobox.cpp # indra/llui/llfolderview.cpp # indra/llui/llfolderviewmodel.h # indra/llui/lllineeditor.cpp # indra/llui/lllineeditor.h # indra/llui/lltextbase.cpp # indra/llui/lltextbase.h # indra/llui/lltexteditor.cpp # indra/llui/lltextvalidate.cpp # indra/llui/lltextvalidate.h # indra/llui/lluictrl.h # indra/llui/llview.cpp # indra/llwindow/llwindowmacosx.cpp # indra/newview/app_settings/settings.xml # indra/newview/llappearancemgr.cpp # indra/newview/llappearancemgr.h # indra/newview/llavatarpropertiesprocessor.cpp # indra/newview/llavatarpropertiesprocessor.h # indra/newview/llbreadcrumbview.cpp # indra/newview/llbreadcrumbview.h # indra/newview/llbreastmotion.cpp # indra/newview/llbreastmotion.h # indra/newview/llconversationmodel.h # indra/newview/lldensityctrl.cpp # indra/newview/lldensityctrl.h # indra/newview/llface.inl # indra/newview/llfloatereditsky.cpp # indra/newview/llfloatereditwater.cpp # indra/newview/llfloateremojipicker.h # indra/newview/llfloaterimsessiontab.cpp # indra/newview/llfloaterprofiletexture.cpp # indra/newview/llfloaterprofiletexture.h # indra/newview/llgesturemgr.cpp # indra/newview/llgesturemgr.h # indra/newview/llimpanel.cpp # indra/newview/llimpanel.h # indra/newview/llinventorybridge.cpp # indra/newview/llinventorybridge.h # indra/newview/llinventoryclipboard.cpp # indra/newview/llinventoryclipboard.h # indra/newview/llinventoryfunctions.cpp # indra/newview/llinventoryfunctions.h # indra/newview/llinventorygallery.cpp # indra/newview/lllistbrowser.cpp # indra/newview/lllistbrowser.h # indra/newview/llpanelobjectinventory.cpp # indra/newview/llpanelprofile.cpp # indra/newview/llpanelprofile.h # indra/newview/llpreviewgesture.cpp # indra/newview/llsavedsettingsglue.cpp # indra/newview/llsavedsettingsglue.h # indra/newview/lltooldraganddrop.cpp # indra/newview/llurllineeditorctrl.cpp # indra/newview/llvectorperfoptions.cpp # indra/newview/llvectorperfoptions.h # indra/newview/llviewerparceloverlay.cpp # indra/newview/llviewertexlayer.cpp # indra/newview/llviewertexturelist.cpp # indra/newview/macmain.h # indra/test/test.cpp
Diffstat (limited to 'indra/llcommon/llthread.cpp')
-rw-r--r--indra/llcommon/llthread.cpp944
1 files changed, 472 insertions, 472 deletions
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 1db97ad3e3..deb1df640c 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -1,472 +1,472 @@
-/**
- * @file llthread.cpp
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010-2013, 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 "linden_common.h"
-#include "llapr.h"
-
-#include "apr_portable.h"
-
-#include "llthread.h"
-#include "llmutex.h"
-
-#include "lltimer.h"
-#include "lltrace.h"
-#include "lltracethreadrecorder.h"
-#include "llexception.h"
-
-#if LL_LINUX
-#include <sched.h>
-#endif
-
-
-#ifdef LL_WINDOWS
-
-const DWORD MS_VC_EXCEPTION=0x406D1388;
-
-#pragma pack(push,8)
-typedef struct tagTHREADNAME_INFO
-{
- DWORD dwType; // Must be 0x1000.
- LPCSTR szName; // Pointer to name (in user addr space).
- DWORD dwThreadID; // Thread ID (-1=caller thread).
- DWORD dwFlags; // Reserved for future use, must be zero.
-} THREADNAME_INFO;
-#pragma pack(pop)
-
-void set_thread_name( DWORD dwThreadID, const char* threadName)
-{
- THREADNAME_INFO info;
- info.dwType = 0x1000;
- info.szName = threadName;
- info.dwThreadID = dwThreadID;
- info.dwFlags = 0;
-
- __try
- {
- ::RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info );
- }
- __except(EXCEPTION_CONTINUE_EXECUTION)
- {
- }
-}
-#endif
-
-
-//----------------------------------------------------------------------------
-// Usage:
-// void run_func(LLThread* thread)
-// {
-// }
-// LLThread* thread = new LLThread();
-// thread->run(run_func);
-// ...
-// thread->setQuitting();
-// while(!timeout)
-// {
-// if (thread->isStopped())
-// {
-// delete thread;
-// break;
-// }
-// }
-//
-//----------------------------------------------------------------------------
-namespace
-{
-
- LLThread::id_t main_thread()
- {
- // Using a function-static variable to identify the main thread
- // requires that control reach here from the main thread before it
- // reaches here from any other thread. We simply trust that whichever
- // thread gets here first is the main thread.
- static LLThread::id_t s_thread_id = LLThread::currentID();
- return s_thread_id;
- }
-
-} // anonymous namespace
-
-LL_COMMON_API bool on_main_thread()
-{
- return (LLThread::currentID() == main_thread());
-}
-
-LL_COMMON_API bool assert_main_thread()
-{
- auto curr = LLThread::currentID();
- auto main = main_thread();
- if (curr == main)
- return true;
-
- LL_WARNS() << "Illegal execution from thread id " << curr
- << " outside main thread " << main << LL_ENDL;
- return false;
-}
-
-// this function has become moot
-void LLThread::registerThreadID() {}
-
-//
-// Handed to the APR thread creation function
-//
-void LLThread::threadRun()
-{
-#ifdef LL_WINDOWS
- set_thread_name(-1, mName.c_str());
-
-#if 0 // probably a bad idea, see usage of SetThreadIdealProcessor in LLWindowWin32)
- HANDLE hThread = GetCurrentThread();
- if (hThread)
- {
- SetThreadAffinityMask(hThread, (DWORD_PTR) 0xFFFFFFFFFFFFFFFE);
- }
-#endif
-
-#endif
-
- LL_PROFILER_SET_THREAD_NAME( mName.c_str() );
-
- // this is the first point at which we're actually running in the new thread
- mID = currentID();
-
- // for now, hard code all LLThreads to report to single master thread recorder, which is known to be running on main thread
- mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder());
-
- // Run the user supplied function
- do
- {
- try
- {
- run();
- }
- catch (const LLContinueError &e)
- {
- LL_WARNS("THREAD") << "ContinueException on thread '" << mName <<
- "' reentering run(). Error what is: '" << e.what() << "'" << LL_ENDL;
- //output possible call stacks to log file.
- LLError::LLCallStacks::print();
-
- LOG_UNHANDLED_EXCEPTION("LLThread");
- continue;
- }
- break;
-
- } while (true);
-
- //LL_INFOS() << "LLThread::staticRun() Exiting: " << threadp->mName << LL_ENDL;
-
-
- delete mRecorder;
- mRecorder = NULL;
-
- // 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),
- mName(name),
- mThreadp(NULL),
- mStatus(STOPPED),
- mRecorder(NULL)
-{
- mRunCondition = new LLCondition();
- mDataLock = new LLMutex();
- mLocalAPRFilePoolp = NULL ;
-}
-
-
-LLThread::~LLThread()
-{
- shutdown();
-
- if (isCrashed())
- {
- LL_WARNS("THREAD") << "Destroying crashed thread named '" << mName << "'" << LL_ENDL;
- }
-
- if(mLocalAPRFilePoolp)
- {
- delete mLocalAPRFilePoolp ;
- mLocalAPRFilePoolp = NULL ;
- }
-}
-
-void LLThread::shutdown()
-{
- if (isCrashed())
- {
- LL_WARNS("THREAD") << "Shutting down crashed thread named '" << mName << "'" << LL_ENDL;
- }
-
- // Warning! If you somehow call the thread destructor from itself,
- // the thread will die in an unclean fashion!
- if (mThreadp)
- {
- if (!isStopped())
- {
- // The thread isn't already stopped
- // First, set the flag that indicates that we're ready to die
- setQuitting();
-
- //LL_INFOS() << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << LL_ENDL;
- // Now wait a bit for the thread to exit
- // It's unclear whether I should even bother doing this - this destructor
- // should never get called unless we're already stopped, really...
- S32 counter = 0;
- const S32 MAX_WAIT = 600;
- while (counter < MAX_WAIT)
- {
- if (isStopped())
- {
- break;
- }
- // Sleep for a tenth of a second
- ms_sleep(100);
- yield();
- counter++;
- }
- }
-
- if (!isStopped())
- {
- // 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(mNativeHandle);
-#endif
-
- delete mRecorder;
- mRecorder = NULL;
- mStatus = STOPPED;
- return;
- }
- mThreadp = NULL;
- }
-
- delete mRunCondition;
- mRunCondition = NULL;
-
- delete mDataLock;
- mDataLock = NULL;
-
- if (mRecorder)
- {
- // missed chance to properly shut down recorder (needs to be done in thread context)
- // probably due to abnormal thread termination
- // so just leak it and remove it from parent
- LLTrace::get_master_thread_recorder()->removeChildRecorder(mRecorder);
- }
-}
-
-
-void LLThread::start()
-{
- llassert(isStopped());
-
- // Set thread state to running
- mStatus = RUNNING;
-
- try
- {
- mThreadp = new std::thread(std::bind(&LLThread::threadRun, this));
- mNativeHandle = mThreadp->native_handle();
- }
- catch (std::system_error& ex)
- {
- mStatus = STOPPED;
- LL_WARNS() << "failed to start thread " << mName << " " << ex.what() << LL_ENDL;
- }
-
-}
-
-//============================================================================
-// Called from MAIN THREAD.
-
-// Request that the thread pause/resume.
-// The thread will pause when (and if) it calls checkPause()
-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
- }
-}
-
-void LLThread::unpause()
-{
- if (mPaused)
- {
- mPaused = 0;
- }
-
- wake(); // wake up the thread if necessary
-}
-
-// virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
-bool LLThread::runCondition(void)
-{
- // by default, always run. Handling of pause/unpause is done regardless of this function's result.
- return true;
-}
-
-//============================================================================
-// Called from run() (CHILD THREAD).
-// Stop thread execution if requested until unpaused.
-void LLThread::checkPause()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
- mDataLock->lock();
-
- // This is in a while loop because the pthread API allows for spurious wakeups.
- while(shouldSleep())
- {
- mDataLock->unlock();
- mRunCondition->wait(); // unlocks mRunCondition
- mDataLock->lock();
- // mRunCondition is locked when the thread wakes up
- }
-
- mDataLock->unlock();
-}
-
-//============================================================================
-
-void LLThread::setQuitting()
-{
- mDataLock->lock();
- if (mStatus == RUNNING)
- {
- mStatus = QUITTING;
- }
- // It's only safe to remove mRunCondition if all locked threads were notified
- mRunCondition->broadcast();
- mDataLock->unlock();
-}
-
-// static
-LLThread::id_t LLThread::currentID()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
- return std::this_thread::get_id();
-}
-
-// static
-void LLThread::yield()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
- std::this_thread::yield();
-}
-
-void LLThread::wake()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
- mDataLock->lock();
- if(!shouldSleep())
- {
- mRunCondition->signal();
- }
- mDataLock->unlock();
-}
-
-void LLThread::wakeLocked()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
- if(!shouldSleep())
- {
- mRunCondition->signal();
- }
-}
-
-void LLThread::lockData()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
- mDataLock->lock();
-}
-
-void LLThread::unlockData()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
- mDataLock->unlock();
-}
-
-//============================================================================
-
-//----------------------------------------------------------------------------
-
-//static
-LLMutex* LLThreadSafeRefCount::sMutex = 0;
-
-//static
-void LLThreadSafeRefCount::initThreadSafeRefCount()
-{
- if (!sMutex)
- {
- sMutex = new LLMutex();
- }
-}
-
-//static
-void LLThreadSafeRefCount::cleanupThreadSafeRefCount()
-{
- delete sMutex;
- sMutex = NULL;
-}
-
-
-//----------------------------------------------------------------------------
-
-LLThreadSafeRefCount::LLThreadSafeRefCount() :
- mRef(0)
-{
-}
-
-LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src)
-{
- mRef = 0;
-}
-
-LLThreadSafeRefCount::~LLThreadSafeRefCount()
-{
- if (mRef != 0)
- {
- LL_ERRS() << "deleting referenced object mRef = " << mRef << LL_ENDL;
- }
-}
-
-//============================================================================
-
-LLResponder::~LLResponder()
-{
-}
-
-//============================================================================
+/**
+ * @file llthread.cpp
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010-2013, 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 "linden_common.h"
+#include "llapr.h"
+
+#include "apr_portable.h"
+
+#include "llthread.h"
+#include "llmutex.h"
+
+#include "lltimer.h"
+#include "lltrace.h"
+#include "lltracethreadrecorder.h"
+#include "llexception.h"
+
+#if LL_LINUX
+#include <sched.h>
+#endif
+
+
+#ifdef LL_WINDOWS
+
+const DWORD MS_VC_EXCEPTION=0x406D1388;
+
+#pragma pack(push,8)
+typedef struct tagTHREADNAME_INFO
+{
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+#pragma pack(pop)
+
+void set_thread_name( DWORD dwThreadID, const char* threadName)
+{
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = threadName;
+ info.dwThreadID = dwThreadID;
+ info.dwFlags = 0;
+
+ __try
+ {
+ ::RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info );
+ }
+ __except(EXCEPTION_CONTINUE_EXECUTION)
+ {
+ }
+}
+#endif
+
+
+//----------------------------------------------------------------------------
+// Usage:
+// void run_func(LLThread* thread)
+// {
+// }
+// LLThread* thread = new LLThread();
+// thread->run(run_func);
+// ...
+// thread->setQuitting();
+// while(!timeout)
+// {
+// if (thread->isStopped())
+// {
+// delete thread;
+// break;
+// }
+// }
+//
+//----------------------------------------------------------------------------
+namespace
+{
+
+ LLThread::id_t main_thread()
+ {
+ // Using a function-static variable to identify the main thread
+ // requires that control reach here from the main thread before it
+ // reaches here from any other thread. We simply trust that whichever
+ // thread gets here first is the main thread.
+ static LLThread::id_t s_thread_id = LLThread::currentID();
+ return s_thread_id;
+ }
+
+} // anonymous namespace
+
+LL_COMMON_API bool on_main_thread()
+{
+ return (LLThread::currentID() == main_thread());
+}
+
+LL_COMMON_API bool assert_main_thread()
+{
+ auto curr = LLThread::currentID();
+ auto main = main_thread();
+ if (curr == main)
+ return true;
+
+ LL_WARNS() << "Illegal execution from thread id " << curr
+ << " outside main thread " << main << LL_ENDL;
+ return false;
+}
+
+// this function has become moot
+void LLThread::registerThreadID() {}
+
+//
+// Handed to the APR thread creation function
+//
+void LLThread::threadRun()
+{
+#ifdef LL_WINDOWS
+ set_thread_name(-1, mName.c_str());
+
+#if 0 // probably a bad idea, see usage of SetThreadIdealProcessor in LLWindowWin32)
+ HANDLE hThread = GetCurrentThread();
+ if (hThread)
+ {
+ SetThreadAffinityMask(hThread, (DWORD_PTR) 0xFFFFFFFFFFFFFFFE);
+ }
+#endif
+
+#endif
+
+ LL_PROFILER_SET_THREAD_NAME( mName.c_str() );
+
+ // this is the first point at which we're actually running in the new thread
+ mID = currentID();
+
+ // for now, hard code all LLThreads to report to single master thread recorder, which is known to be running on main thread
+ mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder());
+
+ // Run the user supplied function
+ do
+ {
+ try
+ {
+ run();
+ }
+ catch (const LLContinueError &e)
+ {
+ LL_WARNS("THREAD") << "ContinueException on thread '" << mName <<
+ "' reentering run(). Error what is: '" << e.what() << "'" << LL_ENDL;
+ //output possible call stacks to log file.
+ LLError::LLCallStacks::print();
+
+ LOG_UNHANDLED_EXCEPTION("LLThread");
+ continue;
+ }
+ break;
+
+ } while (true);
+
+ //LL_INFOS() << "LLThread::staticRun() Exiting: " << threadp->mName << LL_ENDL;
+
+
+ delete mRecorder;
+ mRecorder = NULL;
+
+ // 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),
+ mName(name),
+ mThreadp(NULL),
+ mStatus(STOPPED),
+ mRecorder(NULL)
+{
+ mRunCondition = new LLCondition();
+ mDataLock = new LLMutex();
+ mLocalAPRFilePoolp = NULL ;
+}
+
+
+LLThread::~LLThread()
+{
+ shutdown();
+
+ if (isCrashed())
+ {
+ LL_WARNS("THREAD") << "Destroying crashed thread named '" << mName << "'" << LL_ENDL;
+ }
+
+ if(mLocalAPRFilePoolp)
+ {
+ delete mLocalAPRFilePoolp ;
+ mLocalAPRFilePoolp = NULL ;
+ }
+}
+
+void LLThread::shutdown()
+{
+ if (isCrashed())
+ {
+ LL_WARNS("THREAD") << "Shutting down crashed thread named '" << mName << "'" << LL_ENDL;
+ }
+
+ // Warning! If you somehow call the thread destructor from itself,
+ // the thread will die in an unclean fashion!
+ if (mThreadp)
+ {
+ if (!isStopped())
+ {
+ // The thread isn't already stopped
+ // First, set the flag that indicates that we're ready to die
+ setQuitting();
+
+ //LL_INFOS() << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << LL_ENDL;
+ // Now wait a bit for the thread to exit
+ // It's unclear whether I should even bother doing this - this destructor
+ // should never get called unless we're already stopped, really...
+ S32 counter = 0;
+ const S32 MAX_WAIT = 600;
+ while (counter < MAX_WAIT)
+ {
+ if (isStopped())
+ {
+ break;
+ }
+ // Sleep for a tenth of a second
+ ms_sleep(100);
+ yield();
+ counter++;
+ }
+ }
+
+ if (!isStopped())
+ {
+ // 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(mNativeHandle);
+#endif
+
+ delete mRecorder;
+ mRecorder = NULL;
+ mStatus = STOPPED;
+ return;
+ }
+ mThreadp = NULL;
+ }
+
+ delete mRunCondition;
+ mRunCondition = NULL;
+
+ delete mDataLock;
+ mDataLock = NULL;
+
+ if (mRecorder)
+ {
+ // missed chance to properly shut down recorder (needs to be done in thread context)
+ // probably due to abnormal thread termination
+ // so just leak it and remove it from parent
+ LLTrace::get_master_thread_recorder()->removeChildRecorder(mRecorder);
+ }
+}
+
+
+void LLThread::start()
+{
+ llassert(isStopped());
+
+ // Set thread state to running
+ mStatus = RUNNING;
+
+ try
+ {
+ mThreadp = new std::thread(std::bind(&LLThread::threadRun, this));
+ mNativeHandle = mThreadp->native_handle();
+ }
+ catch (std::system_error& ex)
+ {
+ mStatus = STOPPED;
+ LL_WARNS() << "failed to start thread " << mName << " " << ex.what() << LL_ENDL;
+ }
+
+}
+
+//============================================================================
+// Called from MAIN THREAD.
+
+// Request that the thread pause/resume.
+// The thread will pause when (and if) it calls checkPause()
+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
+ }
+}
+
+void LLThread::unpause()
+{
+ if (mPaused)
+ {
+ mPaused = 0;
+ }
+
+ wake(); // wake up the thread if necessary
+}
+
+// virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
+bool LLThread::runCondition(void)
+{
+ // by default, always run. Handling of pause/unpause is done regardless of this function's result.
+ return true;
+}
+
+//============================================================================
+// Called from run() (CHILD THREAD).
+// Stop thread execution if requested until unpaused.
+void LLThread::checkPause()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
+ mDataLock->lock();
+
+ // This is in a while loop because the pthread API allows for spurious wakeups.
+ while(shouldSleep())
+ {
+ mDataLock->unlock();
+ mRunCondition->wait(); // unlocks mRunCondition
+ mDataLock->lock();
+ // mRunCondition is locked when the thread wakes up
+ }
+
+ mDataLock->unlock();
+}
+
+//============================================================================
+
+void LLThread::setQuitting()
+{
+ mDataLock->lock();
+ if (mStatus == RUNNING)
+ {
+ mStatus = QUITTING;
+ }
+ // It's only safe to remove mRunCondition if all locked threads were notified
+ mRunCondition->broadcast();
+ mDataLock->unlock();
+}
+
+// static
+LLThread::id_t LLThread::currentID()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
+ return std::this_thread::get_id();
+}
+
+// static
+void LLThread::yield()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
+ std::this_thread::yield();
+}
+
+void LLThread::wake()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
+ mDataLock->lock();
+ if(!shouldSleep())
+ {
+ mRunCondition->signal();
+ }
+ mDataLock->unlock();
+}
+
+void LLThread::wakeLocked()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
+ if(!shouldSleep())
+ {
+ mRunCondition->signal();
+ }
+}
+
+void LLThread::lockData()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
+ mDataLock->lock();
+}
+
+void LLThread::unlockData()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
+ mDataLock->unlock();
+}
+
+//============================================================================
+
+//----------------------------------------------------------------------------
+
+//static
+LLMutex* LLThreadSafeRefCount::sMutex = 0;
+
+//static
+void LLThreadSafeRefCount::initThreadSafeRefCount()
+{
+ if (!sMutex)
+ {
+ sMutex = new LLMutex();
+ }
+}
+
+//static
+void LLThreadSafeRefCount::cleanupThreadSafeRefCount()
+{
+ delete sMutex;
+ sMutex = NULL;
+}
+
+
+//----------------------------------------------------------------------------
+
+LLThreadSafeRefCount::LLThreadSafeRefCount() :
+ mRef(0)
+{
+}
+
+LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src)
+{
+ mRef = 0;
+}
+
+LLThreadSafeRefCount::~LLThreadSafeRefCount()
+{
+ if (mRef != 0)
+ {
+ LL_ERRS() << "deleting referenced object mRef = " << mRef << LL_ENDL;
+ }
+}
+
+//============================================================================
+
+LLResponder::~LLResponder()
+{
+}
+
+//============================================================================