From 1cadeb40df15c1eaef3410064f9a2b8e4489082d Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 6 Sep 2016 21:25:57 -0400
Subject: [PATCH] MAINT-5232: Prevent runaway LLSingletonBase::MasterList
 growth.

Until we reimplement LLCoros on Boost.Fiber, we must hand-implement
coroutine-local data. That presently takes the form of a map keyed on
llcoro::id, whose values are the stacks of currently-initializing LLSingleton
instances.

But since the viewer launches an open-ended number of coroutines, we could end
up with an open-ended number of map entries unless we intentionally prune the
map. So every time we pop the stack to empty, remove that map entry.

This could result in thrashing, a given coroutine's 'initializing' stack being
created and deleted for almost every LLSingleton instantiated by that
coroutine -- but the number of different LLSingletons is necessarily static,
and the lifespan of each is the entire rest of the process. Even a couple
dozen LLSingletons won't thrash that badly.
---
 indra/llcommon/llsingleton.cpp | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
index 3f65820f2ed..24ccc8ddb42 100644
--- a/indra/llcommon/llsingleton.cpp
+++ b/indra/llcommon/llsingleton.cpp
@@ -94,6 +94,15 @@ class LLSingletonBase::MasterList:
         // here. It returns a reference to the selected mapped_type instance.
         return mInitializing[llcoro::get_id()];
     }
+
+    void cleanup_initializing_()
+    {
+        InitializingMap::iterator found = mInitializing.find(llcoro::get_id());
+        if (found != mInitializing.end())
+        {
+            mInitializing.erase(found);
+        }
+    }
 };
 
 //static
@@ -129,7 +138,7 @@ LLSingletonBase::list_t& LLSingletonBase::get_initializing()
 //static
 LLSingletonBase::list_t& LLSingletonBase::get_initializing_from(MasterList* master)
 {
-    return master->get_initializing_();;
+    return master->get_initializing_();
 }
 
 LLSingletonBase::~LLSingletonBase() {}
@@ -156,6 +165,17 @@ void LLSingletonBase::pop_initializing()
     // and pop it
     list.pop_back();
 
+    // The viewer launches an open-ended number of coroutines. While we don't
+    // expect most of them to initialize LLSingleton instances, our present
+    // get_initializing() logic could lead to an open-ended number of map
+    // entries. So every time we pop the stack back to empty, delete the entry
+    // entirely.
+    if (list.empty())
+    {
+        MasterList::instance().cleanup_initializing_();
+    }
+
+    // Now validate the newly-popped LLSingleton.
     if (back != this)
     {
         logerrs("Push/pop mismatch in stack of currently-initializing LLSingletons: ",
-- 
GitLab