Skip Menu |

This queue is for tickets about the IO-Async CPAN distribution.

Report information
The Basics
Id: 102044
Status: resolved
Priority: 0/
Queue: IO-Async

People
Owner: Nobody in particular
Requestors: TEAM [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 0.64
Fixed in: 0.65



Subject: Watching handles and O_NONBLOCK
So as suggested, I put a quick patch in to report when ->watch_io is given a blocking filehandle, and we seem to hit that a few times in tests... not sure whether the loop should silently "fix" that. The warning triggers 414 times in the core IO::Async testsuite, many of those will be duplicates but it does seem to indicate that there's a few paths to cover. cheers, Tom
Subject: 2015-02-10-report-blocking-fh.diff
diff --git a/lib/IO/Async/Loop/Poll.pm b/lib/IO/Async/Loop/Poll.pm index a1154d3..7af2a28 100644 --- a/lib/IO/Async/Loop/Poll.pm +++ b/lib/IO/Async/Loop/Poll.pm @@ -246,6 +246,18 @@ sub watch_io my $poll = $self->{poll}; my $handle = $params{handle}; + { + use Fcntl qw(F_GETFL O_NONBLOCK); + + my $flags = fcntl($handle, F_GETFL, 0) + or die "Can't get flags for the socket: $!\n"; + warn sprintf("Watching a handle in blocking mode [%s] from %s\n", $handle, join(':', (caller)[1,2])) unless O_NONBLOCK == ($flags & O_NONBLOCK); + + if(0) { # might want to try this as well...? + $flags = fcntl($handle, F_SETFL, $flags | O_NONBLOCK) + or die "Can't set flags for the socket: $!\n"; + } + } my $curmask = $poll->mask( $handle ) || 0; diff --git a/lib/IO/Async/Loop/Select.pm b/lib/IO/Async/Loop/Select.pm index 37ff60d..55660bd 100644 --- a/lib/IO/Async/Loop/Select.pm +++ b/lib/IO/Async/Loop/Select.pm @@ -241,6 +241,19 @@ sub watch_io my %params = @_; $self->__watch_io( %params ); + { + my $handle = $params{handle}; + use Fcntl qw(F_GETFL O_NONBLOCK); + + my $flags = fcntl($handle, F_GETFL, 0) + or die "Can't get flags for the socket: $!\n"; + warn sprintf("Watching a handle in blocking mode [%s] from %s\n", $handle, join(':', (caller)[1,2])) unless O_NONBLOCK == ($flags & O_NONBLOCK); + + if(0) { # might want to try this as well...? + $flags = fcntl($handle, F_SETFL, $flags | O_NONBLOCK) + or die "Can't set flags for the socket: $!\n"; + } + } my $fileno = $params{handle}->fileno;
Subject: blocking.log

Message body is not shown because it is too large.

Testing some app code with the attached patch applied, will update this ticket if anything breaks.
Subject: 2015-02-10-make-handle-nonblocking.diff
diff --git a/lib/IO/Async/Loop.pm b/lib/IO/Async/Loop.pm index a59a2e6..36d467d 100644 --- a/lib/IO/Async/Loop.pm +++ b/lib/IO/Async/Loop.pm @@ -2629,6 +2629,22 @@ sub _manage_queues return $count; } +sub _make_handle_nonblocking { + my ($self, $handle) = @_; + require Fcntl; + + my $flags = fcntl($handle, Fcntl::F_GETFL, 0) + or die "Can't get flags for the socket: $!\n"; + + unless(Fcntl::O_NONBLOCK == ($flags & Fcntl::O_NONBLOCK)) { + require IO::Async::Notifier; + IO::Async::Notifier->debug_printf("Applying O_NONBLOCK to handle in blocking mode [%s] from %s\n", $handle, join(':', (caller)[1,2])); + $flags = fcntl($handle, Fcntl::F_SETFL, $flags | Fcntl::O_NONBLOCK) + or die "Can't set flags for the socket: $!\n"; + } + $handle +} + =head1 EXTENSIONS An Extension is a Perl module that provides extra methods in the diff --git a/lib/IO/Async/Loop/Poll.pm b/lib/IO/Async/Loop/Poll.pm index a1154d3..a42959b 100644 --- a/lib/IO/Async/Loop/Poll.pm +++ b/lib/IO/Async/Loop/Poll.pm @@ -246,6 +246,7 @@ sub watch_io my $poll = $self->{poll}; my $handle = $params{handle}; + $self->_make_handle_nonblocking($handle); my $curmask = $poll->mask( $handle ) || 0; diff --git a/lib/IO/Async/Loop/Select.pm b/lib/IO/Async/Loop/Select.pm index 37ff60d..6401295 100644 --- a/lib/IO/Async/Loop/Select.pm +++ b/lib/IO/Async/Loop/Select.pm @@ -241,6 +241,7 @@ sub watch_io my %params = @_; $self->__watch_io( %params ); + $self->_make_handle_nonblocking($params{handle}); my $fileno = $params{handle}->fileno;
On Tue Feb 10 12:10:09 2015, TEAM wrote: Show quoted text
> So as suggested, I put a quick patch in to report when ->watch_io is > given a blocking filehandle, and we seem to hit that a few times in > tests... not sure whether the loop should silently "fix" that.
As discussed on IRC, seems to be easiest just to fix it. So here we are -- Paul Evans
Subject: rt102044.patch
=== modified file 'lib/IO/Async/Loop.pm' --- lib/IO/Async/Loop.pm 2015-02-14 21:59:45 +0000 +++ lib/IO/Async/Loop.pm 2015-02-14 22:05:36 +0000 @@ -2011,6 +2011,10 @@ Applications should use a C<IO::Async::Handle> or C<IO::Async::Stream> instead of using this method. +If the filehandle does not yet have the C<O_NONBLOCK> flag set, it will be +enabled by this method. This will ensure that any subsequent C<sysread>, +C<syswrite>, or similar will not block on the filehandle. + =cut # This class specifically does NOT implement this method, so that subclasses @@ -2023,6 +2027,9 @@ my $handle = delete $params{handle} or croak "Expected 'handle'"; defined eval { $handle->fileno } or croak "Expected that 'handle' has defined ->fileno"; + # Silent "upgrade" to O_NONBLOCK + $handle->blocking and $handle->blocking(0); + my $watch = ( $self->{iowatches}->{$handle->fileno} ||= [] ); $watch->[0] = $handle;
Released in 0.65 -- Paul Evans