Skip Menu |

This queue is for tickets about the IO CPAN distribution.

Report information
The Basics
Id: 46836
Status: resolved
Priority: 0/
Queue: IO

People
Owner: Nobody in particular
Requestors: appfault [...] hotmail.com
Cc:
AdminCc:

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



Subject: All of the IO::Socket socket tests are broken with respect to signal interrupts
All of the IO::Socket socket tests are broken with respect to signal interrupts. For instance, SIGCHLD, as seen in the attached test script. At a minimum there needs to be a retry on the EINTR errno.
Subject: lwp_eintr_test.pl
#!/usr/bin/perl -w use strict; use warnings; use LWP::UserAgent; my $test_duration_seconds = 5; $| = 1; $SIG{CHLD} = sub { }; # comment out this line and the bug will not occur my $start_test_time = time(); if (!fork()) { while (time() < $start_test_time + $test_duration_seconds) { if (!fork()) { exit 0; } } exit 0; } { my $ua = new LWP::UserAgent; my $iterations = 0; while (time() < $start_test_time + $test_duration_seconds) { sub callback($$$) { } my $request = HTTP::Request->new('GET', 'http://www.perl.org/favicon.ico'); my $response = $ua->request($request, \&callback, 4096); if ($response->is_error()) { die("Couldn't get - returned ".$response->code()." ".$response->as_string()."\n"); } $iterations++; print('.'); } die if $iterations < 1; print("success ($iterations iterations)\n"); } exit 0;
Subject: Re: [rt.cpan.org #46836] All of the IO::Socket socket tests are broken with respect to signal interrupts
Date: Wed, 10 Jun 2009 16:23:49 -0500
To: bug-IO [...] rt.cpan.org
From: Graham Barr <gbarr [...] pobox.com>
On Jun 10, 2009, at 4:16 PM, appfault via RT wrote: Show quoted text
> All of the IO::Socket socket tests are broken with respect to signal > interrupts. For instance, SIGCHLD, as seen in the attached test > script.
Are you suggesting the test suite it broken and fails its tests ? If so patches welcome. Show quoted text
> At a minimum there needs to be a retry on the EINTR errno.
I do not believe that it is the place of IO::Socket to to do the restart based on EINTR, that is a decision for the application, or code using IO::Socket, to make. Graham.
By "IO::Socket socket tests" I meant the test functions that rely on the select perl call. The specific list that I see is: IO::Select::can_read() IO::Select::can_write() IO::Select::has_exception() If it's really your contention that the caller of the functions must check the global $! variable, populated by select(), to look for select() errors which IO::Select does not report, then at a minimum that needs to be documented.
Also, if it's the caller's responsibility to check for that condition, then this is still a bug in the IO module, only it would be a bug in (at a minimum) IO/Socket.pm where it uses the can_write() function and assumes that a failure is a critical failure, without checking for the possible (undocumented in IO::Select) non-critical EINTR failure.
Subject: Re: [rt.cpan.org #46836] All of the IO::Socket socket tests are broken with respect to signal interrupts
Date: Wed, 10 Jun 2009 17:42:15 -0500
To: bug-IO [...] rt.cpan.org
From: Graham Barr <gbarr [...] pobox.com>
So you are saying there is a bug in IO::Select, your original report did not make that clear. I would agree that IO::Select should handle EINTR patches welcome
From: appfault [...] hotmail.com
I've improved the test's failure rate with the bug in place, and in doing so noticed there was a second much less common issue in LWP/Protocol/http.pm which previously fails to make use of the IO::Socket library. With that patch the test now succeeds.
#!/usr/bin/perl -w use strict; use warnings; use LWP::UserAgent (); use Time::HiRes (); my $test_duration_seconds = 10; $| = 1; $SIG{CHLD} = sub { }; # comment out this line and the bug will not occur my $start_test_time = time(); my $pid = fork(); if ($pid) { use POSIX (); while (time() < $start_test_time + $test_duration_seconds) { die if kill(POSIX::SIGCHLD(), $pid) != 1; Time::HiRes::sleep(.1); waitpid(-1, POSIX::WNOHANG()); } waitpid(-1, 0); exit 0; } { my $ua = new LWP::UserAgent; my $iterations = 0; while (time() < $start_test_time + $test_duration_seconds) { sub callback($$$) { } my $request = HTTP::Request->new('GET', 'http://www.perl.org/favicon.ico'); my $response = $ua->request($request, \&callback, 4096); if ($response->is_error()) { die("Get failed ".$response->code()." ".$response->as_string()."\n"); } $iterations++; print('.'); } die if $iterations < 1; print("success ($iterations iterations)\n"); } exit 0;
--- LWP/Protocol/http.pm 2009-06-22 18:21:21.000000000 +0000 +++ LWP/Protocol/http.pm 2009-06-22 18:21:31.000000000 +0000 @@ -9,6 +9,7 @@ require HTTP::Response; require HTTP::Status; require Net::HTTP; +use IO::Select (); use vars qw(@ISA @EXTRA_SOCK_OPTS); @@ -387,7 +388,7 @@ my($self, $timeout) = @_; my $fbits = ''; vec($fbits, fileno($self), 1) = 1; - my $nfound = select($fbits, undef, undef, $timeout); + my $nfound = IO::Select::select_wroi($fbits, undef, undef, $timeout); die "select failed: $!" unless defined $nfound; return $nfound > 0; } --- IO/Select.pm 2009-06-22 18:07:38.000000000 +0000 +++ IO/Select.pm 2009-06-22 18:21:17.000000000 +0000 @@ -96,13 +96,23 @@ $count; } +# select with retry on interrupt +sub select_wroi($$$$) { + my ($r, $w, $e, $timeout) = @_; + for (;;) { + my ($nfound, $timeleft) = select($r, $w, $e, $timeout); + return $nfound if $nfound >= 0; + $timeout = $timeleft if ($timeleft > 0); + Carp::croak("select: $!") unless $!{EINTR}; + } +} + sub can_read { my $vec = shift; my $timeout = shift; my $r = $vec->[VEC_BITS]; - - defined($r) && (select($r,undef,undef,$timeout) > 0) + defined($r) && (select_wroi($r,undef,undef,$timeout) > 0) ? handles($vec, $r) : (); } @@ -113,7 +123,7 @@ my $timeout = shift; my $w = $vec->[VEC_BITS]; - defined($w) && (select(undef,$w,undef,$timeout) > 0) + defined($w) && (select_wroi(undef,$w,undef,$timeout) > 0) ? handles($vec, $w) : (); } @@ -124,7 +134,7 @@ my $timeout = shift; my $e = $vec->[VEC_BITS]; - defined($e) && (select(undef,undef,$e,$timeout) > 0) + defined($e) && (select_wroi(undef,undef,$e,$timeout) > 0) ? handles($vec, $e) : (); }
Ticket migrated to github as https://github.com/toddr/IO/issues/34