summaryrefslogtreecommitdiff
path: root/indra/llcommon/llcoros.cpp
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2019-10-24 12:54:38 -0400
committerNat Goodspeed <nat@lindenlab.com>2020-03-25 19:02:24 -0400
commitcbf146f2b3fc255bc83f2b01101dc29658bea6ea (patch)
treeda7bc386376e825eda480dc166495434543d5fcd /indra/llcommon/llcoros.cpp
parent7541e784d991888d6f600f4cb9439d5fcf15e452 (diff)
DRTVWR-476: Pump coroutines a few more times when we start quitting.
By the time "LLApp" listeners are notified that the app is quitting, the mainloop is no longer running. Even though those listeners do things like close work queues and inject exceptions into pending promises, any coroutines waiting on those resources must regain control before they can notice and shut down properly. Add a final "LLApp" listener that resumes ready coroutines a few more times. Make sure every other "LLApp" listener is positioned before that new one.
Diffstat (limited to 'indra/llcommon/llcoros.cpp')
-rw-r--r--indra/llcommon/llcoros.cpp32
1 files changed, 32 insertions, 0 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()