io.c: fix infinite retry

* io.c (io_binwritev): fix infinite retry when flushing buffered
  data.  [Feature #9323]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60373 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2017-10-23 05:28:12 +00:00
parent 71a7ef31d7
commit 08524bc594
2 changed files with 23 additions and 13 deletions

24
io.c
View File

@ -1534,7 +1534,7 @@ io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
}
else {
iov++;
iovcnt--;
if (!--iovcnt) return 0;
}
retry:
@ -1557,23 +1557,23 @@ io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
fptr->wbuf.len -= r;
}
else {
written_len -= fptr->wbuf.len;
fptr->wbuf.off = 0;
fptr->wbuf.len = 0;
}
}
if (written_len == total) return written_len;
if (written_len == total) return total;
for (i = 0; i < iovcnt; i++) {
if (r > (ssize_t)iov[i].iov_len) {
r -= iov[i].iov_len;
iov[i].iov_len = 0;
}
else {
iov[i].iov_base = (char *)iov[i].iov_base + r;
iov[i].iov_len -= r;
break;
}
while (r >= (ssize_t)iov->iov_len) {
/* iovcnt > 0 */
r -= iov->iov_len;
iov->iov_len = 0;
iov++;
if (!--iovcnt) return total;
/* defensive check: written_len should == total */
}
iov->iov_base = (char *)iov->iov_base + r;
iov->iov_len -= r;
errno = EAGAIN;
}

View File

@ -1236,6 +1236,16 @@ class TestIO < Test::Unit::TestCase
open(file, "rb") do |r|
assert_equal([line, line, "\n"], r.readlines)
end
line = "x"*99+"\n"
open(file, "wb") do |w|
w.write(line*81) # 8100 bytes
assert_equal(100, w.write("a"*99, "\n"))
end
open(file, "rb") do |r|
81.times {assert_equal(line, r.gets)}
assert_equal("a"*99+"\n", r.gets)
end
end
end