summaryrefslogtreecommitdiff
path: root/indra/llcommon/llerrorcontrol.h
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2019-10-07 17:18:29 -0400
committerNat Goodspeed <nat@lindenlab.com>2020-03-25 18:47:13 -0400
commite4d6383c47241fa4c58c2491c2d32046126fe52c (patch)
tree3d5e816e61cd9c3830cce0b0c82e1a161e024d4a /indra/llcommon/llerrorcontrol.h
parent16b768370b8587f63231f9bbc06ab48b58a4f15e (diff)
DRTVWR-476: Fix overflow case in llcoro::postAndSuspend().
Actually the fix is in postAndSuspendSetup(), which affects postAndSuspend(), postAndSuspendWithTimeout(), suspendUntilEventOnWithTimeout() and suspendUntilEventOn(). By "overflow case" we mean the special circumstance in which: * the LLEventPump in question is an LLEventMailDrop, meaning its listeners eventually expect to see every post()ed value * one of the listeners is supposed to consume those values (has called LLCoros::set_consuming(true)) * post() is called more than once before that listener is resumed. The magic of postAndSuspend() (et al.) is a temporary LLCoros::Promise. The waiting coroutine calls get() on the corresponding Future, causing it to suspend (as promised) until the Promise is fulfilled. With the Boost.Fiber implementation of coroutines, fulfilling the Promise doesn't immediately resume the suspended coroutine -- it merely marks it ready to resume, next time the scheduler gets control. A second post() call before the suspended coroutine is resumed results in a second call to Promise::set_value(). But Promise is a one-shot entity. This results in a promise_already_satisfied exception. Because a second post() call during that time window is perfectly reasonable, we catch that exception and carry on. The tricky part is: when that exception is thrown, what should the listener return? Previously we were returning the listener's current consuming setting, just as when the set_value() call succeeds. But when the LLEventPump is an LLEventMailDrop, and the listener's consuming flag is true, that told LLEventMailDrop::post() that the value got through, and that it needn't bother to save it in its history queue. The net effect was to discard the value. Instead, return the listener's consuming flag only when Promise::set_value() succeeds. When it throws promise_already_satisfied, unconditionally return false. That directs LLEventMailDrop::post() to enqueue the undelivered value so that the *next* suspendUntilEventOn() call can pick it up.
Diffstat (limited to 'indra/llcommon/llerrorcontrol.h')
0 files changed, 0 insertions, 0 deletions