summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/llcoros.cpp32
-rw-r--r--indra/llcommon/llcoros.h3
-rw-r--r--indra/llcommon/lleventcoro.cpp5
-rw-r--r--indra/llmessage/llcoproceduremanager.cpp9
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)
{