Skip to content

Instantly share code, notes, and snippets.

@jjn1056
Created August 26, 2026 20:33
Show Gist options
  • Select an option

  • Save jjn1056/f2dbe746a598c6e6e23febb2dafc3f3e to your computer and use it in GitHub Desktop.

Select an option

Save jjn1056/f2dbe746a598c6e6e23febb2dafc3f3e to your computer and use it in GitHub Desktop.
Using Future::OP with _DefaultImpl or not?
Hit this working on an async redis client - a pubsub message handler
disconnects two connections, which cancels both their in-flight reads,
and with the default impl that dies:
Can't call method "fh" on an undefined value at Future/IO.pm line 890
Best I can tell the poll loop caches $npollers and then completes ready
futures inside the loop, so when a continuation cancels other pending
reads, on_cancel splices them out of @pollers behind the loop's back and
the index runs off the end.
Boiled it down to this. On the stock default impl it dies every time;
run the same script with -MFuture::IO::Impl::IOAsync and it completes
fine, so it looks specific to _DefaultImpl's poll loop:
use v5.36;
use Socket;
use Future::IO;
my (@rd, @wr);
for (0..2) {
socketpair my $r, my $w, AF_UNIX, SOCK_STREAM, PF_UNSPEC or die $!;
push @rd, $r;
push @wr, $w;
}
my @f = map { Future::IO->read($_, 10) } @rd;
$f[0]->on_done(sub { $f[1]->cancel; $f[2]->cancel });
syswrite $wr[0], "hello";
$f[0]->get;
say "completed without error";
I patched my local copy to collect the ready pollers during the scan and
fire ->done after it finishes (with an is_ready guard) and that fixes the
repro, plus my app's full test suite passes on it. Happy to send the
patch if you want.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment