Subject: | Poll returning NVAL after removing handle from loop |
This is (related to?) the issue that snappy raised in IRC yesterday.
It seems that a combination of:
* fork() - due to name resolver process, for example
* IO::Async::Stream->close on a stream that's been attached to the loop
leaves a closed filehandle in the poll() list:
$ IO_ASYNC_LOOP=Poll strace -epoll -ff perl 2015-04-24-io-async-poll-nval.pl
Process 32078 attached
[pid 32077] poll([{fd=8, events=POLLIN}, {fd=5, events=POLLIN}, {fd=7, events=POLLIN}], 3, 4294967295) = 1 ([{fd=5, revents=POLLIN}])
[pid 32077] poll([{fd=8, events=POLLIN}, {fd=7, events=POLLIN}, {fd=5, events=POLLIN}, {fd=3, events=POLLOUT}], 4, 29994) = 1 ([{fd=3, revents=POLLOUT}])
IO::Async::Stream=HASH(0x203e948) at 2015-04-24-io-async-poll-nval.pl line 33.
[pid 32077] poll([{fd=8, events=POLLIN}, {fd=7, events=POLLIN}, {fd=5, events=POLLIN}, {fd=3, events=POLLIN|POLLOUT}], 4, 29993) = 1 ([{fd=3, revents=POLLOUT}])
[pid 32077] poll([{fd=8, events=POLLIN}, {fd=7, events=POLLIN}, {fd=5, events=POLLIN}, {fd=3, events=0}], 4, 4294967295) = 1 ([{fd=3, revents=POLLNVAL}])
[pid 32077] poll([{fd=8, events=POLLIN}, {fd=7, events=POLLIN}, {fd=5, events=POLLIN}, {fd=3, events=0}], 4, 4294967295) = 1 ([{fd=3, revents=POLLNVAL}])
[pid 32077] poll([{fd=8, events=POLLIN}, {fd=7, events=POLLIN}, {fd=5, events=POLLIN}, {fd=3, events=0}], 4, 4294967295) = 1 ([{fd=3, revents=POLLNVAL}])
[pid 32077] poll([{fd=8, events=POLLIN}, {fd=7, events=POLLIN}, {fd=5, events=POLLIN}, {fd=3, events=0}], 4, 4294967295) = 1 ([{fd=3, revents=POLLNVAL}])
[pid 32077] poll([{fd=8, events=POLLIN}, {fd=7, events=POLLIN}, {fd=5, events=POLLIN}, {fd=3, events=0}], 4, 4294967295) = 1 ([{fd=3, revents=POLLNVAL}])
[pid 32077] poll([{fd=8, events=POLLIN}, {fd=7, events=POLLIN}, {fd=5, events=POLLIN}, {fd=3, events=0}], 4, 4294967295) = 1 ([{fd=3, revents=POLLNVAL}])
If either of those two conditions aren't met - connect via IP, for example, or not closing the handle - things seem fine.
Not sure yet if this just applies to poll(), but so far it's 100% reproducible on 0.66. Note that it doesn't cause any visible problems in the attached script; this is just based on strace output.
cheers,
Tom
Subject: | 2015-04-24-io-async-poll-nval.pl |
#!/usr/bin/env perl
use strict;
use warnings;
use IO::Async::Loop;
use IO::Async::Stream;
for(1..2) {
my $loop = IO::Async::Loop->new;
my ($conn) = $loop->connect(
# host => '1.2.3.4' or addr => { ... } avoids the resolver fork, and does not
# exhibit and problems. as soon as we hit a name lookup, poll() starts returning
# POLLNVAL for fd3
# addr => {
# ip => '127.0.0.1',
# port => 80,
# socktype => 'stream',
# family => 'inet',
# },
host => 'localhost',
service => 80,
socktype => 'stream',
)->get;
$loop->add(
my $stream = IO::Async::Stream->new(
handle => $conn,
on_read => sub { }
)
);
warn $stream;
$stream->write('GET /')->get;
$stream->close;
}