diff --git a/MANIFEST b/MANIFEST index ef3406c4c7ae..508216f8dbc5 100644 --- a/MANIFEST +++ b/MANIFEST @@ -6404,6 +6404,7 @@ t/op/range.t See if .. works t/op/read.t See if read() works t/op/readdir.t See if readdir() works t/op/readline.t See if <> / readline / rcatline work +t/op/readline_nb.t Test <> error handling on non-blocking handles t/op/recurse.t See if deep recursion works t/op/ref.t See if refs and objects work t/op/refstack.t See if a ref counted stack fixes things diff --git a/pp_hot.c b/pp_hot.c index 641bedc42569..d0dce393eaba 100644 --- a/pp_hot.c +++ b/pp_hot.c @@ -3994,6 +3994,21 @@ PP(pp_match) return NORMAL; } +/* errno can be either EAGAIN or EWOULDBLOCK for a socket() read that + is non-blocking but would have blocked if blocking +*/ +PERL_STATIC_INLINE bool +error_is_would_block(int err) { +#ifdef EAGAIN + if (err == EAGAIN) + return true; +#endif +#ifdef EWOULDBLOCK + if (err == EWOULDBLOCK) + return true; +#endif + return false; +} /* Perl_do_readline(): implement <$fh>, readline($fh) and glob('*.h') * @@ -4236,6 +4251,9 @@ Perl_do_readline(pTHX) (STATUS_CURRENT & 0x80) ? ", core dumped" : ""); } } + else if (error_is_would_block(errno)) { + PerlIO_clearerr(fp); + } if (gimme == G_SCALAR) { if (type != OP_RCATLINE) { diff --git a/t/op/readline_nb.t b/t/op/readline_nb.t new file mode 100644 index 000000000000..8c8037eefd07 --- /dev/null +++ b/t/op/readline_nb.t @@ -0,0 +1,36 @@ +#!./perl + +BEGIN { + chdir 't' if -d 't'; + require './test.pl'; + set_up_inc('../lib'); + require Config; Config->import; + + skip_all_if_miniperl(); +} + +use strict; +use IO::Select; + +$Config{d_pipe} + or skip_all("No pipe"); + +my ($in, $out); +pipe($in, $out) + or skip_all("Cannot pipe: $!"); + +$in->blocking(0) + or skip_all("Cannot make pipe non-blocking"); + +my $line = <$in>; +is($line, undef, "error reading"); +ok(!$in->error, "but did not set error flag"); +close $out; +$line = <$in>; +is($line, undef, "nothing to read, but eof"); +ok(!$in->error, "still did not set error flag"); +ok($in->eof, "did set eof"); +ok(close($in), "close success"); + + +done_testing();