diff options
-rw-r--r-- | indra/llcommon/llcoros.cpp | 32 | ||||
-rw-r--r-- | indra/llcommon/llcoros.h | 3 | ||||
-rw-r--r-- | indra/llcommon/lleventcoro.cpp | 5 | ||||
-rw-r--r-- | indra/llmessage/llcoproceduremanager.cpp | 9 |
4 files changed, 45 insertions, 4 deletions
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 78a0c5d225..ea54f1aa92 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -128,6 +128,38 @@ LLCoros::LLCoros(): mStackSize(256*1024) #endif { + // Set up a listener to notice when the viewer is starting to shut down. + // Store the connection in an LLTempBoundListener so it will automatically + // disconnect. + mAppListener = LLEventPumps::instance().obtain("LLApp").listen( + "final", // must be the LAST listener on this LLEventPump + [this](const LLSD& status) + { + if (status["status"].asString() == "quitting") + { + // Other LLApp status-change listeners do things like close + // work queues and inject the Stop exception into pending + // promises, to force coroutines waiting on those things to + // notice and terminate. The only problem is that by the time + // LLApp sets "quitting" status, the main loop has stopped + // pumping the fiber scheduler with yield() calls. A waiting + // coroutine still might not wake up until after resources on + // which it depends have been freed. Pump it a few times + // ourselves. Of course, stop pumping as soon as the last of + // the coroutines has terminated. + for (size_t count = 0; count < 10 && ! mCoros.empty(); ++count) + { + // don't use llcoro::suspend() because that module depends + // on this one + boost::this_fiber::yield(); + } + } + // If we're really the last listener, it shouldn't matter whether + // we consume this event -- but our being last depends on every + // other listen() call specifying before "final", which would be + // all too easy to forget. So do not consume the event. + return false; + }); } LLCoros::~LLCoros() diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index de7b691284..171d1ebd2a 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -34,6 +34,7 @@ #include <boost/fiber/future/promise.hpp> #include <boost/fiber/future/future.hpp> #include "llsingleton.h" +#include "llevents.h" #include <boost/ptr_container/ptr_map.hpp> #include <boost/function.hpp> #include <string> @@ -284,6 +285,8 @@ private: typedef boost::ptr_map<std::string, CoroData> CoroMap; CoroMap mCoros; + LLTempBoundListener mAppListener; + // Identify the current coroutine's CoroData. This local_ptr isn't static // because it's a member of an LLSingleton, and we rely on it being // cleaned up in proper dependency order. diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 967c4d74d8..785c231f2c 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -153,6 +153,7 @@ postAndSuspendSetup(const std::string& callerName, // The relative order of the two listen() calls below would only matter if // "LLApp" were an LLEventMailDrop. But if we ever go there, we'd want to // notice the pending LLApp status first. + // Run this listener before the "final" listener. LLBoundListener stopper( LLEventPumps::instance().obtain("LLApp").listen( listenerName, @@ -181,7 +182,9 @@ postAndSuspendSetup(const std::string& callerName, } // do not consume -- every listener must see status return false; - })); + }, + LLEventPump::NameList{}, // after + LLEventPump::NameList{ "final "})); // before LLBoundListener connection( replyPump.listen( listenerName, diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index a8f6b8aa67..a71a31bfd2 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -218,8 +218,9 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), mCoroMapping() { - // store in our LLTempBoundListener so that when the LLCoprocedurePool is - // destroyed, we implicitly disconnect from this LLEventPump + // Store in our LLTempBoundListener so that when the LLCoprocedurePool is + // destroyed, we implicitly disconnect from this LLEventPump. + // Run this listener before the "final" listener. mStatusListener = LLEventPumps::instance().obtain("LLApp").listen( poolName, [this, poolName](const LLSD& status) @@ -235,7 +236,9 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): mPendingCoprocs.close(); } return false; - }); + }, + LLEventPump::NameList{}, // after + LLEventPump::NameList{ "final "}); // before for (size_t count = 0; count < mPoolSize; ++count) { |