summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike <contact@mikelittman.me>2026-10-22 11:36:21 -0400
committerGitHub <noreply@github.com>2026-10-22 23:36:21 +0800
commitf2a1ad0e53632ad69729c9bd55edcdfe8ef98368 (patch)
tree3c323a88a92d145dab4bd11f5e432bcefe0a796e
parentb087c0c8d818bace45a9d0d2dec3661f1261896d (diff)
Do not abort when a shutdown thread joins itself (#37)
std::thread::join throws system_error if the caller is the thread being joined. That uncaught exception aborted the process during shutdown. Detach the current thread instead, and catch a join that still throws.
-rw-r--r--indra/llcommon/llthread.h26
-rw-r--r--indra/llcommon/threadpool.cpp12
-rw-r--r--indra/llcorehttp/llwebsocketmgr.cpp3
-rw-r--r--indra/llwebrtc/llwebrtc.cpp23
-rw-r--r--indra/newview/llinventorymodel.cpp3
5 files changed, 63 insertions, 4 deletions
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index b97d479abc..38a5f4669f 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -33,6 +33,32 @@
extern void set_thread_name(const char* threadName);
+// Join unless this is the calling thread. Joining the current thread throws
+// system_error(resource_deadlock_would_occur) and aborts via std::terminate.
+inline void ll_join_thread(std::thread& thread)
+{
+ if (!thread.joinable())
+ {
+ return;
+ }
+ if (thread.get_id() == std::this_thread::get_id())
+ {
+ thread.detach();
+ return;
+ }
+ try
+ {
+ thread.join();
+ }
+ catch (const std::system_error&)
+ {
+ if (thread.joinable())
+ {
+ thread.detach();
+ }
+ }
+}
+
namespace LLTrace
{
class ThreadRecorder;
diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
index 6adbdffba8..668c8ba598 100644
--- a/indra/llcommon/threadpool.cpp
+++ b/indra/llcommon/threadpool.cpp
@@ -20,6 +20,7 @@
#include "commoncontrol.h"
#include "llerror.h"
#include "llevents.h"
+#include "llthread.h"
#include "llsd.h"
#include "stringize.h"
@@ -127,8 +128,17 @@ void LL::ThreadPoolBase::close()
{
if (pair.second.joinable())
{
+ // close() runs on a worker when the LLApp status listener
+ // fires on that thread. Joining it throws and aborts shutdown.
+ if (pair.second.get_id() == std::this_thread::get_id())
+ {
+ LL_WARNS("ThreadPool") << mName << " detaching current thread "
+ << pair.first << LL_ENDL;
+ pair.second.detach();
+ continue;
+ }
LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
- pair.second.join();
+ ll_join_thread(pair.second);
}
}
LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL;
diff --git a/indra/llcorehttp/llwebsocketmgr.cpp b/indra/llcorehttp/llwebsocketmgr.cpp
index ef07295eed..701fbd5446 100644
--- a/indra/llcorehttp/llwebsocketmgr.cpp
+++ b/indra/llcorehttp/llwebsocketmgr.cpp
@@ -28,6 +28,7 @@
#include "llwebsocketmgr.h"
#include "llerror.h"
+#include "llthread.h"
#include "llsdserialize.h"
#include "llhost.h"
#include "llsdjson.h"
@@ -508,7 +509,7 @@ void LLWebsocketMgr::WSServer::stop()
<< "thread-boundary regression." << LL_ENDL;
}
- mServerThread.join();
+ ll_join_thread(mServerThread);
LL_INFOS("WebSocket") << "WebSocket server thread joined for: " << mServerName << LL_ENDL;
}
onStopped();
diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp
index d07f801051..ff68437cf3 100644
--- a/indra/llwebrtc/llwebrtc.cpp
+++ b/indra/llwebrtc/llwebrtc.cpp
@@ -29,6 +29,7 @@
#include <chrono>
#include <future>
#include <thread>
+#include <system_error>
#include <string.h>
#include "api/audio/create_audio_device_module.h"
#include "api/audio_codecs/audio_decoder_factory.h"
@@ -558,7 +559,27 @@ bool LLWebRTCImpl::terminate()
return false;
}
- shutdown_thread.join();
+ // Joining the current thread throws system_error and aborts the process.
+ if (shutdown_thread.get_id() == std::this_thread::get_id())
+ {
+ RTC_LOG(LS_WARNING) << __FUNCTION__ << ": shutdown thread is the caller; detaching.";
+ shutdown_thread.detach();
+ }
+ else
+ {
+ try
+ {
+ shutdown_thread.join();
+ }
+ catch (const std::system_error& e)
+ {
+ RTC_LOG(LS_WARNING) << __FUNCTION__ << ": join failed: " << e.what();
+ if (shutdown_thread.joinable())
+ {
+ shutdown_thread.detach();
+ }
+ }
+ }
webrtc::LogMessage::RemoveLogToStream(mLogSink);
return true;
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index b818a66b30..31fd699335 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -31,6 +31,7 @@
#include <thread>
#include "llinventorymodel.h"
+#include "llthread.h"
#include "llaisapi.h"
#include "llagent.h"
@@ -2505,7 +2506,7 @@ void LLInventoryModel::waitForPendingCacheWrites()
{
if (thread.joinable())
{
- thread.join();
+ ll_join_thread(thread);
}
}
sPendingCacheThreads.clear();