diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/llcommon/llthread.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (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.cpp | 944 |
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()
+{
+}
+
+//============================================================================
|