socket: sendmsg/recvmsg only retries blocking on errors

* ext/socket/ancdata.c (bsock_sendmsg_internal): only retry on error
  (bsock_recvmsg_internal): ditto
* test/socket/test_unix.rb: test above for infinite loop

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45066 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2014-02-21 00:55:13 +00:00
Родитель f404c1022c
Коммит d691a28d91
3 изменённых файлов: 37 добавлений и 10 удалений

Просмотреть файл

@ -1,3 +1,9 @@
Fri Feb 21 09:48:56 2014 Eric Wong <e@80x24.org>
* ext/socket/ancdata.c (bsock_sendmsg_internal): only retry on error
(bsock_recvmsg_internal): ditto
* test/socket/test_unix.rb: test above for infinite loop
Fri Feb 21 08:27:19 2014 Eric Wong <e@80x24.org>
* include/ruby/ruby.h (RB_GC_GUARD):

Просмотреть файл

@ -1282,12 +1282,11 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
ss = rb_sendmsg(fptr->fd, &mh, flags);
if (!nonblock && rb_io_wait_writable(fptr->fd)) {
rb_io_check_closed(fptr);
goto retry;
}
if (ss == -1) {
if (!nonblock && rb_io_wait_writable(fptr->fd)) {
rb_io_check_closed(fptr);
goto retry;
}
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "sendmsg(2) would block");
rb_sys_fail("sendmsg(2)");
@ -1601,12 +1600,11 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
ss = rb_recvmsg(fptr->fd, &mh, flags);
if (!nonblock && rb_io_wait_readable(fptr->fd)) {
rb_io_check_closed(fptr);
goto retry;
}
if (ss == -1) {
if (!nonblock && rb_io_wait_readable(fptr->fd)) {
rb_io_check_closed(fptr);
goto retry;
}
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvmsg(2) would block");
#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)

Просмотреть файл

@ -5,6 +5,7 @@ end
require "test/unit"
require "tempfile"
require "timeout"
require "tmpdir"
require "thread"
require "io/nonblock"
@ -369,6 +370,28 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
s2.close if s2
end
def test_dgram_pair_sendrecvmsg_errno_set
s1, s2 = to_close = UNIXSocket.pair(Socket::SOCK_DGRAM)
pipe = IO.pipe
to_close.concat(pipe)
set_errno = lambda do
begin
pipe[0].read_nonblock(1)
fail
rescue => e
assert(IO::EAGAINWaitReadable === e)
end
end
Timeout.timeout(10) do
set_errno.call
assert_equal(2, s1.sendmsg("HI"))
set_errno.call
assert_equal("HI", s2.recvmsg[0])
end
ensure
to_close.each(&:close) if to_close
end
def test_epipe # [ruby-dev:34619]
s1, s2 = UNIXSocket.pair
s1.shutdown(Socket::SHUT_WR)