summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorMike <contact@mikelittman.me>2026-10-08 06:47:32 -0500
committerGitHub <noreply@github.com>2026-10-08 19:47:32 +0800
commitc538254fbd77df962b627460d863911aa2196988 (patch)
tree7ad27e28d217108acb12fb199492550e106c3ea5 /indra/llcommon
parent55922ee44aad5824e9b18bba750ec06736c87e62 (diff)
Do not recreate destroyed singletons during shutdown (#31)
deleteAll() used to let getInstance() build a replacement, which crashed when the script-editor server posted a toast after LLUI was gone. Shutdown now refuses that construction, and notification adds do nothing once the notification system is gone.
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/llsingleton.cpp13
-rw-r--r--indra/llcommon/llsingleton.h17
2 files changed, 30 insertions, 0 deletions
diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
index 05dc3cde79..46659e6b7b 100644
--- a/indra/llcommon/llsingleton.cpp
+++ b/indra/llcommon/llsingleton.cpp
@@ -27,6 +27,8 @@
#include "linden_common.h"
#include "llsingleton.h"
+#include <atomic>
+
#include "llerror.h"
#include "llerrorcontrol.h"
#include "lldependencies.h"
@@ -406,8 +408,19 @@ void LLSingletonBase::cleanup_()
}
//static
+namespace
+{
+ std::atomic<bool> sShuttingDown{false};
+}
+
+bool LLSingletonBase::shuttingDown()
+{
+ return sShuttingDown.load(std::memory_order_acquire);
+}
+
void LLSingletonBase::deleteAll()
{
+ sShuttingDown.store(true, std::memory_order_release);
// It's essential to traverse these in dependency order.
for (LLSingletonBase* sp : dep_sort())
{
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index ebef2489ce..c088f7a9c4 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -46,6 +46,9 @@ class LLSingletonBase
{
public:
class MasterList;
+ // True once deleteAll() has started. getInstance() must not construct
+ // a replacement for a singleton that shutdown has already destroyed.
+ static bool shuttingDown();
LLSingletonBase(const LLSingletonBase&) = delete;
LLSingletonBase& operator=(const LLSingletonBase&) = delete;
@@ -533,6 +536,13 @@ public:
case DELETED:
// called after deleteSingleton()
+ if (LLSingletonBase::shuttingDown())
+ {
+ logwarns({"Refusing to recreate deleted singleton ",
+ classname<DERIVED_TYPE>(),
+ " during shutdown"});
+ return nullptr;
+ }
logwarns({"Trying to access deleted singleton ",
classname<DERIVED_TYPE>(),
" -- creating new instance"});
@@ -540,6 +550,13 @@ public:
[[fallthrough]];
case UNINITIALIZED:
case QUEUED:
+ if (LLSingletonBase::shuttingDown())
+ {
+ logwarns({"Refusing to construct singleton ",
+ classname<DERIVED_TYPE>(),
+ " during shutdown"});
+ return nullptr;
+ }
// QUEUED means some secondary thread has already requested an
// instance, but for present purposes that's semantically
// identical to UNINITIALIZED: either way, we must ourselves