From 3be79d5371c291264b12ecb3bf8daf0761bf1123 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 23 May 2013 16:28:20 -0400
Subject: [PATCH] MAINT-2724: Make viewer explicitly set coroutine stack size.
 Introduce LLCoros::setStackSize(), with a compile-time default value we hope
 we never have to use. Make LLAppViewer call it with the value of the new
 settings variable CoroutineStackSize as soon as we've read settings files.
 (While we're at it, notify interested parties that we've read settings
 files.) Give CoroutineStackSize a default value four times the previous
 default stack size. Make LLCoros::launch() pass the saved stack size to each
 new coroutine instance. Re-enable lleventcoro integration test. Use LLSDMap()
 construct rather than LLSD::insert(), which used to return the modified
 object but is now void.

---
 indra/llcommon/CMakeLists.txt             |  1 +
 indra/llcommon/llcoros.cpp                | 13 +++++++-
 indra/llcommon/llcoros.h                  |  6 +++-
 indra/llcommon/tests/lleventcoro_test.cpp | 37 ++++++++++++++++-------
 indra/newview/app_settings/settings.xml   | 11 +++++++
 indra/newview/llappviewer.cpp             | 12 ++++++++
 6 files changed, 67 insertions(+), 13 deletions(-)

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 95b1d536fe0..3a4a8facc21 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -337,6 +337,7 @@ if (LL_TESTS)
   LL_ADD_INTEGRATION_TEST(reflection "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}")
+  LL_ADD_INTEGRATION_TEST(lleventcoro "" "${test_libs};${BOOST_CONTEXT_LIBRARY}")
   LL_ADD_INTEGRATION_TEST(llprocess "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llstreamqueue "" "${test_libs}")
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 91227043060..a629f71d4b9 100755
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -39,7 +39,12 @@
 #include "llerror.h"
 #include "stringize.h"
 
-LLCoros::LLCoros()
+LLCoros::LLCoros():
+    // MAINT-2724: default coroutine stack size too small on Windows.
+    // Previously we used
+    // boost::context::guarded_stack_allocator::default_stacksize();
+    // empirically this is 64KB on Windows and Linux. Try quadrupling.
+    mStackSize(256*1024)
 {
     // Register our cleanup() method for "mainloop" ticks
     LLEventPumps::instance().obtain("mainloop").listen(
@@ -125,6 +130,12 @@ std::string LLCoros::getNameByID(const void* self_id) const
     return "";
 }
 
+void LLCoros::setStackSize(S32 stacksize)
+{
+    LL_INFOS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL;
+    mStackSize = stacksize;
+}
+
 /*****************************************************************************
 *   MUST BE LAST
 *****************************************************************************/
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
index 03df406b688..01ee11da1ac 100755
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -125,7 +125,7 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
     template <typename CALLABLE>
     std::string launch(const std::string& prefix, const CALLABLE& callable)
     {
-        return launchImpl(prefix, new coro(callable));
+        return launchImpl(prefix, new coro(callable, mStackSize));
     }
 
     /**
@@ -152,6 +152,9 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
     /// getName() by self.get_id()
     std::string getNameByID(const void* self_id) const;
 
+    /// for delayed initialization
+    void setStackSize(S32 stacksize);
+
 private:
     friend class LLSingleton<LLCoros>;
     LLCoros();
@@ -159,6 +162,7 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
     std::string generateDistinctName(const std::string& prefix) const;
     bool cleanup(const LLSD&);
 
+    S32 mStackSize;
     typedef boost::ptr_map<std::string, coro> CoroMap;
     CoroMap mCoros;
 };
diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp
index 8d12529613e..5ebde1a31df 100755
--- a/indra/llcommon/tests/lleventcoro_test.cpp
+++ b/indra/llcommon/tests/lleventcoro_test.cpp
@@ -78,6 +78,7 @@
 
 #include "../test/lltut.h"
 #include "llsd.h"
+#include "llsdutil.h"
 #include "llevents.h"
 #include "tests/wrapllerrs.h"
 #include "stringize.h"
@@ -108,7 +109,7 @@ match_substring(BidirectionalIterator begin,
 		BidirectionalIterator end, 
 		std::string xmatch,
 		BOOST_DEDUCED_TYPENAME coroutine<BidirectionalIterator(void)>::self& self) { 
-  BidirectionalIterator begin_ = begin;
+//BidirectionalIterator begin_ = begin;
   for(; begin != end; ++begin) 
     if(match(begin, end, xmatch)) {
       self.yield(begin);
@@ -213,7 +214,7 @@ namespace tut
             BEGIN
             {
                 result = postAndWait(self,
-                                     LLSD().insert("value", 17), // request event
+                                     LLSDMap("value", 17),       // request event
                                      immediateAPI.getPump(),     // requestPump
                                      "reply1",                   // replyPump
                                      "reply");                   // request["reply"] = name
@@ -226,7 +227,7 @@ namespace tut
             BEGIN
             {
                 LLEventWithID pair = ::postAndWait2(self,
-                                                    LLSD().insert("value", 18),
+                                                    LLSDMap("value", 18),
                                                     immediateAPI.getPump(),
                                                     "reply2",
                                                     "error2",
@@ -244,7 +245,7 @@ namespace tut
             BEGIN
             {
                 LLEventWithID pair = ::postAndWait2(self,
-                                                    LLSD().insert("value", 18).insert("fail", LLSD()),
+                                                    LLSDMap("value", 18)("fail", LLSD()),
                                                     immediateAPI.getPump(),
                                                     "reply2",
                                                     "error2",
@@ -273,7 +274,7 @@ namespace tut
             BEGIN
             {
                 LLCoroEventPump waiter;
-                result = waiter.postAndWait(self, LLSD().insert("value", 17),
+                result = waiter.postAndWait(self, LLSDMap("value", 17),
                                             immediateAPI.getPump(), "reply");
             }
             END
@@ -365,7 +366,7 @@ namespace tut
             BEGIN
             {
                 LLCoroEventPumps waiter;
-                LLEventWithID pair(waiter.postAndWait(self, LLSD().insert("value", 23),
+                LLEventWithID pair(waiter.postAndWait(self, LLSDMap("value", 23),
                                                       immediateAPI.getPump(), "reply", "error"));
                 result = pair.first;
                 which  = pair.second;
@@ -379,7 +380,7 @@ namespace tut
             {
                 LLCoroEventPumps waiter;
                 LLEventWithID pair(
-                    waiter.postAndWait(self, LLSD().insert("value", 23).insert("fail", LLSD()),
+                    waiter.postAndWait(self, LLSDMap("value", 23)("fail", LLSD()),
                                        immediateAPI.getPump(), "reply", "error"));
                 result = pair.first;
                 which  = pair.second;
@@ -392,7 +393,7 @@ namespace tut
             BEGIN
             {
                 LLCoroEventPumps waiter;
-                result = waiter.postAndWaitWithException(self, LLSD().insert("value", 8),
+                result = waiter.postAndWaitWithException(self, LLSDMap("value", 8),
                                                          immediateAPI.getPump(), "reply", "error");
             }
             END
@@ -406,7 +407,7 @@ namespace tut
                 try
                 {
                     result = waiter.postAndWaitWithException(self,
-                        LLSD().insert("value", 9).insert("fail", LLSD()),
+                        LLSDMap("value", 9)("fail", LLSD()),
                         immediateAPI.getPump(), "reply", "error");
                     debug("no exception");
                 }
@@ -424,7 +425,7 @@ namespace tut
             BEGIN
             {
                 LLCoroEventPumps waiter;
-                result = waiter.postAndWaitWithLog(self, LLSD().insert("value", 30),
+                result = waiter.postAndWaitWithLog(self, LLSDMap("value", 30),
                                                    immediateAPI.getPump(), "reply", "error");
             }
             END
@@ -439,7 +440,7 @@ namespace tut
                 try
                 {
                     result = waiter.postAndWaitWithLog(self,
-                        LLSD().insert("value", 31).insert("fail", LLSD()),
+                        LLSDMap("value", 31)("fail", LLSD()),
                         immediateAPI.getPump(), "reply", "error");
                     debug("no exception");
                 }
@@ -796,4 +797,18 @@ namespace tut
         ensure("no result", result.isUndefined());
         ensure_contains("got error", threw, "32");
     }
+}
+
+/*==========================================================================*|
+#include <boost/context/guarded_stack_allocator.hpp>
+
+namespace tut
+{
+    template<> template<>
+    void object::test<23>()
+    {
+        set_test_name("stacksize");
+        std::cout << "default_stacksize: " << boost::context::guarded_stack_allocator::default_stacksize() << '\n';
+    }
 } // namespace tut
+|*==========================================================================*/
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index b3538bf069e..f356cff9d89 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1905,6 +1905,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>CoroutineStackSize</key>
+    <map>
+      <key>Comment</key>
+      <string>Size (in bytes) for each coroutine stack</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>262144</integer>
+    </map>
     <key>CreateToolCopyCenters</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 45a990f65f1..fdc2cdb78db 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -117,6 +117,7 @@
 
 #include "llleap.h"
 #include "stringize.h"
+#include "llcoros.h"
 
 // Third party library includes
 #include <boost/bind.hpp>
@@ -755,6 +756,7 @@ bool LLAppViewer::init()
 
 	//set the max heap size.
 	initMaxHeapSize() ;
+	LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize"));
 
 	LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled"), (U32)gSavedSettings.getU32("MemoryPrivatePoolSize")*1024*1024) ;
 
@@ -2810,6 +2812,16 @@ bool LLAppViewer::initConfiguration()
 
 	loadColorSettings();
 
+	// Let anyone else who cares know that we've populated our settings
+	// variables.
+	for (LLControlGroup::key_iter ki(LLControlGroup::beginKeys()), kend(LLControlGroup::endKeys());
+		 ki != kend; ++ki)
+	{
+		// For each named instance of LLControlGroup, send an event saying
+		// we've initialized an LLControlGroup instance by that name.
+		LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", *ki));
+	}
+
 	return true; // Config was successful.
 }
 
-- 
GitLab