Skip to content
Permalink
Browse files

Avoid notification queue growth in Channel.Supply

If the code that `tap`s the Supply then does a `send` on the Channel,
then that will happen synchronously with the loop pulling from the
Channel. The result is that the loop never ends. However, to avoid
races in other situations, we subscribe to the async notifications of
new items in the Channel before starting that loop. Since we cannot
process any `whenever` events until setup logic is complete, this will
cause those events to queue up, causing memory growth.

This helps with #2803.
  • Loading branch information...
jnthn committed Apr 5, 2019
1 parent 7b4dd30 commit d5044de2f7c2101ae6a24da8263ce8e1bd41dc81
Showing with 11 additions and 2 deletions.
  1. +11 −2 src/core/Channel.pm6
@@ -135,8 +135,17 @@ my class Channel does Awaitable {
# it's important to do this after tapping the supply, or a
# value sent between us draining it and doing the tap would
# not result in a notification, and so we'd not emit it on
# the supply. This lost event can then cause a deadlock.
loop {
# the supply. This lost event can then cause a deadlock. We
# also limit ourselves to fetching up to the number of items
# currently in the channel before we started; any further
# ones will result in an async notification. If we don't, and
# the code we `emit` to itself synchronously adds things, then
# we can end up with the async notifications piling up becuase

This comment has been minimized.

Copy link
@vendethiel

vendethiel Apr 8, 2019

Contributor

"becuase"

# the `whenever` above never gets chance to run. Note that we
# may be competing over the items currently in the queue, so the
# `last if ...` check in this loop is still essential.
my int $initial-items = nqp::elems($!queue);
while $initial-items-- {
my Mu \got = self.poll;
last if nqp::eqaddr(got, Nil);
emit got;

0 comments on commit d5044de

Please sign in to comment.
You can’t perform that action at this time.