-
Notifications
You must be signed in to change notification settings - Fork 13
Description
This is a follow up of
rakudo/rakudo#5141
and
rakudo/rakudo#5158
Consider the following piece of code:
my $p = Promise.new;
my $s1 = supply {
await $p;
say "processing whenever"
};
react {
whenever $s1 { }
$p.keep;
say "end of react block";
}
That piece of code prints
end of react block
processing whenever
This is unexpected. The order seems reversed. Why is this so?
By default whenevers tap their supply instantly and as a result run the supply block they are connected to. This has a potential for deadlocking when that supply block (or one nested via more whenevers
) contains an emit
as the emit
will call the whenever block of the original supply, but by definition only a single execution branch is allowed in a supply block at any time.
Possibly (I'm not sure about that) there are other scenarios posing similar deadlock issues without recursion being involved.
The currently implemented solution for this deadlock problem in rakudo/rakudo@26a9c31 and rakudo/rakudo@5478392 works as follows. When - in the setup phase, during the processing of a whenever tapping - an await happens (be it a protect, acquire, lock or plain await) a continuation starting at the root of the whenever tapping is taken. Only after the supply block itself finished running the continuation is resumed. So the order in which the code is executed is dependent on whether there is any locking going on in code tapped by the whenever.
This behavior is difficult for a unknowing programmer to follow. Even a programmer knowing about this behavior will potentially have a hard time knowing whether there is a lock somewhere in the tapped code that could cause this reordering of code. This is a case of action-at-a-distance.
Also there still is a possibility of the code deadlocking left. That's detailed in rakudo/rakudo#5141. I consider that a problem separate from this issue.