io.c: workaround for EPROTOTYPE
* io.c (internal_write_func, internal_writev_func): retry at unexpected EPROTOTYPE on macOS, to get rid of a kernel bug. [ruby-core:86690] [Bug #14713] * ext/socket/init.c (rsock_{sendto,send,write}_blocking): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63304 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
9cd4834810
commit
7727b22eb1
@ -68,6 +68,12 @@ is_socket(int fd)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined __APPLE__
|
||||||
|
# define do_write_retry(code) do {ret = code;} while (ret == -1 && errno == EPROTOTYPE)
|
||||||
|
#else
|
||||||
|
# define do_write_retry(code) ret = code
|
||||||
|
#endif
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rsock_init_sock(VALUE sock, int fd)
|
rsock_init_sock(VALUE sock, int fd)
|
||||||
{
|
{
|
||||||
@ -95,8 +101,10 @@ rsock_sendto_blocking(void *data)
|
|||||||
{
|
{
|
||||||
struct rsock_send_arg *arg = data;
|
struct rsock_send_arg *arg = data;
|
||||||
VALUE mesg = arg->mesg;
|
VALUE mesg = arg->mesg;
|
||||||
return (VALUE)sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
|
ssize_t ret;
|
||||||
arg->flags, arg->to, arg->tolen);
|
do_write_retry(sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
|
||||||
|
arg->flags, arg->to, arg->tolen));
|
||||||
|
return (VALUE)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
@ -104,8 +112,10 @@ rsock_send_blocking(void *data)
|
|||||||
{
|
{
|
||||||
struct rsock_send_arg *arg = data;
|
struct rsock_send_arg *arg = data;
|
||||||
VALUE mesg = arg->mesg;
|
VALUE mesg = arg->mesg;
|
||||||
return (VALUE)send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
|
ssize_t ret;
|
||||||
arg->flags);
|
do_write_retry(send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
|
||||||
|
arg->flags));
|
||||||
|
return (VALUE)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct recvfrom_arg {
|
struct recvfrom_arg {
|
||||||
@ -378,10 +388,18 @@ rsock_write_nonblock(VALUE sock, VALUE str, VALUE ex)
|
|||||||
rb_io_flush(sock);
|
rb_io_flush(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
again:
|
||||||
|
#endif
|
||||||
n = (long)send(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str), MSG_DONTWAIT);
|
n = (long)send(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str), MSG_DONTWAIT);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
int e = errno;
|
int e = errno;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (e == EPROTOTYPE) {
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (e == EWOULDBLOCK || e == EAGAIN) {
|
if (e == EWOULDBLOCK || e == EAGAIN) {
|
||||||
if (ex == Qfalse) return sym_wait_writable;
|
if (ex == Qfalse) return sym_wait_writable;
|
||||||
rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e,
|
rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e,
|
||||||
|
13
io.c
13
io.c
@ -945,11 +945,18 @@ internal_read_func(void *ptr)
|
|||||||
return read(iis->fd, iis->buf, iis->capa);
|
return read(iis->fd, iis->buf, iis->capa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined __APPLE__
|
||||||
|
# define do_write_retry(code) do {ret = code;} while (ret == -1 && errno == EPROTOTYPE)
|
||||||
|
#else
|
||||||
|
# define do_write_retry(code) ret = code
|
||||||
|
#endif
|
||||||
static VALUE
|
static VALUE
|
||||||
internal_write_func(void *ptr)
|
internal_write_func(void *ptr)
|
||||||
{
|
{
|
||||||
struct io_internal_write_struct *iis = ptr;
|
struct io_internal_write_struct *iis = ptr;
|
||||||
return write(iis->fd, iis->buf, iis->capa);
|
ssize_t ret;
|
||||||
|
do_write_retry(write(iis->fd, iis->buf, iis->capa));
|
||||||
|
return (VALUE)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
@ -963,7 +970,9 @@ static VALUE
|
|||||||
internal_writev_func(void *ptr)
|
internal_writev_func(void *ptr)
|
||||||
{
|
{
|
||||||
struct io_internal_writev_struct *iis = ptr;
|
struct io_internal_writev_struct *iis = ptr;
|
||||||
return writev(iis->fd, iis->iov, iis->iovcnt);
|
ssize_t ret;
|
||||||
|
do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
|
||||||
|
return (VALUE)ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -425,7 +425,7 @@ class FTPTest < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
conn.print(l, "\r\n")
|
conn.print(l, "\r\n")
|
||||||
end
|
end
|
||||||
rescue Errno::EPIPE, Errno::EPROTOTYPE
|
rescue Errno::EPIPE
|
||||||
ensure
|
ensure
|
||||||
assert_nil($!)
|
assert_nil($!)
|
||||||
conn.close
|
conn.close
|
||||||
|
@ -452,7 +452,7 @@ class TestWEBrickHTTPServer < Test::Unit::TestCase
|
|||||||
TCPSocket.open(addr, port) do |c|
|
TCPSocket.open(addr, port) do |c|
|
||||||
c.write("GET / HTTP/1.0\r\n")
|
c.write("GET / HTTP/1.0\r\n")
|
||||||
junk = -"X-Junk: #{' ' * 1024}\r\n"
|
junk = -"X-Junk: #{' ' * 1024}\r\n"
|
||||||
assert_raise(Errno::ECONNRESET, Errno::EPIPE, Errno::EPROTOTYPE) do
|
assert_raise(Errno::ECONNRESET, Errno::EPIPE) do
|
||||||
loop { c.write(junk) }
|
loop { c.write(junk) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user