Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

await on a Supply .head .Promise never fires (but Supplier.head.Promise does) #4824

Closed
p6rt opened this issue Dec 5, 2015 · 5 comments
Closed

Comments

@p6rt
Copy link

p6rt commented Dec 5, 2015

Migrated from rt.perl.org#126824 (status was 'resolved')

Searchable as RT126824$

@p6rt
Copy link
Author

p6rt commented Dec 5, 2015

From @skids

16​:18 skids I think the Supply work may have made $fh.watch.Promise not fire anymore.
16​:20 watch.tap still works.
16​:21 jnthn The semantics of Supply.Promise changed
16​:21 You'll need $fh.watch.head(1).Promise to get the original ones
16​:21 skids Ah that would explain it. jnthn++
16​:22 Hrm that doesn't seem to do it though.
  2 more elements. Show/hide.
16​:34 jnthn Hm, head doesn't seem to be filing the "done"

These work​:

$ perl6 -e 'my $f = Supplier.new; my $s = $f.head(1).Supply; my $t = $s.tap(-> $ { 42.say }, done => {43.say} ); start { for 0..3 { $f.emit(42) }; $f.done(); }; await $s.Promise; 44.say; '
42
43
44

$ perl6 -e 'my $f = Supplier.new; my $s = $f.head(1).Supply; my $t = $s.tap(-> $ { 42.say }, done => {43.say} ); start { for 0..3 { $f.emit(42) }; }; await $s.Promise; 44.say; '
42
43
44

This neither sends a done nor fulfills a .Promise (input echoed into file from another terminal)​:

$ perl6 -e 'my $fh = open("/tmp/foo.txt", :create); my $s = $fh.watch.head(1); my $t = $s.tap(-> $ { 42.say }, done => {43.say} ); await $s.Promise; 44.say'
42
^C

...and when the .head is off a Supply instead of a Supplier, a done from the original Supply propagates but the Promise never unhooks​:

$ perl6 -e 'my $f = Supplier.new; my $s = $f.Supply.head(1); my $t = $s.tap(-> $ { 42.say }, done => {43.say} ); start { for 0..3 { $f.emit(42) }; $f.done(); }; await $s.Promise; 44.say; '
42
43
^C

$ perl6 -e 'my $f = Supplier.new; my $s = $f.Supply.head(1); my $t = $s.tap(-> $ { 42.say }, done => {43.say} ); start { for 0..3 { $f.emit(42) }; }; await $s.Promise; 44.say; '
42
^C

@p6rt
Copy link
Author

p6rt commented Nov 2, 2016

From @jnthn

On Sat Dec 05 11​:13​:54 2015, bri@​abrij.org wrote​:

16​:18 skids I think the Supply work may have made
$fh.watch.Promise not fire anymore.
16​:20 watch.tap still works.
16​:21 jnthn The semantics of Supply.Promise changed
16​:21 You'll need $fh.watch.head(1).Promise to get the
original ones
16​:21 skids Ah that would explain it. jnthn++
16​:22 Hrm that doesn't seem to do it though.
2 more elements. Show/hide.
16​:34 jnthn Hm, head doesn't seem to be filing the "done"

These work​:

$ perl6 -e 'my $f = Supplier.new; my $s = $f.head(1).Supply; my $t =
$s.tap(-> $ { 42.say }, done => {43.say} ); start { for 0..3 {
$f.emit(42) }; $f.done(); }; await $s.Promise; 44.say; '
42
43
44

$ perl6 -e 'my $f = Supplier.new; my $s = $f.head(1).Supply; my $t =
$s.tap(-> $ { 42.say }, done => {43.say} ); start { for 0..3 {
$f.emit(42) }; }; await $s.Promise; 44.say; '
42
43
44

This neither sends a done nor fulfills a .Promise (input echoed into
file from another terminal)​:

$ perl6 -e 'my $fh = open("/tmp/foo.txt", :create); my $s =
$fh.watch.head(1); my $t = $s.tap(-> $ { 42.say }, done => {43.say} );
await $s.Promise; 44.say'
42
^C

This works reliably now, and so could do with a test. Probably thanks to one of the many Supply fixes over the last months.

...and when the .head is off a Supply instead of a Supplier, a done
from the original Supply propagates but the Promise never unhooks​:

$ perl6 -e 'my $f = Supplier.new; my $s = $f.Supply.head(1); my $t =
$s.tap(-> $ { 42.say }, done => {43.say} ); start { for 0..3 {
$f.emit(42) }; $f.done(); }; await $s.Promise; 44.say; '
42
43
^C

$ perl6 -e 'my $f = Supplier.new; my $s = $f.Supply.head(1); my $t =
$s.tap(-> $ { 42.say }, done => {43.say} ); start { for 0..3 {
$f.emit(42) }; }; await $s.Promise; 44.say; '
42
^C

This code is vulnerable to a race condition, thus it sometimes works, sometimes not. If you add a `sleep 1` before the `await` then it reliably hangs. The reason is that a Supplier is a live supply; if you miss the events (emit/done) then they're gone for good. (Note that `.Promise` taps the supply separately from the `.tap` that is already taking place.) For this to reliably work, the `Promise` should be obtained prior to setting off the `start` block. This works reliably, every time​:

my $f = Supplier.new;
my $s = $f.Supply.head(1);
my $t = $s.tap(-> $ { 42.say }, done => {43.say} );
my $p = $s.Promise;
start {
  for 0..3 {
  $f.emit(42)
  };
  $f.done();
}
await $p;
44.say;

Tagging testneeded for the part that deserves a test.

/jnthn

@p6rt
Copy link
Author

p6rt commented Nov 2, 2016

The RT System itself - Status changed from 'new' to 'open'

@p6rt
Copy link
Author

p6rt commented Dec 31, 2016

@p6rt p6rt closed this as completed Dec 31, 2016
@p6rt
Copy link
Author

p6rt commented Dec 31, 2016

@moritz - Status changed from 'open' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant