mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Reduce chance to receive EBADF when closing an IO from another thread.
This commit is contained in:
parent
587f501c7c
commit
3a8cadcf8f
Notes:
git
2021-08-08 19:12:39 +09:00
1 changed files with 27 additions and 19 deletions
46
io.c
46
io.c
|
@ -1422,6 +1422,13 @@ rb_thread_fd_writable(int fd)
|
|||
|
||||
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
|
||||
{
|
||||
// fptr->fd can be set to -1 at any time by another thread when the GVL is
|
||||
// released. Many code, e.g. `io_bufread` didn't check this correctly and
|
||||
// instead relies on `read(-1) -> -1` which causes this code path. We then
|
||||
// check here whether the IO was in fact closed. Probably it's better to
|
||||
// check that `fptr->fd != -1` before using it in syscall.
|
||||
rb_io_check_closed(RFILE(io)->fptr);
|
||||
|
||||
switch (error) {
|
||||
// In old Linux, several special files under /proc and /sys don't handle
|
||||
// select properly. Thus we need avoid to call if don't use O_NONBLOCK.
|
||||
|
@ -2646,31 +2653,32 @@ io_bufread(char *ptr, long len, rb_io_t *fptr)
|
|||
long c;
|
||||
|
||||
if (READ_DATA_PENDING(fptr) == 0) {
|
||||
while (n > 0) {
|
||||
while (n > 0) {
|
||||
again:
|
||||
c = rb_read_internal(fptr->fd, ptr+offset, n);
|
||||
if (c == 0) break;
|
||||
if (c < 0) {
|
||||
rb_io_check_closed(fptr);
|
||||
c = rb_read_internal(fptr->fd, ptr+offset, n);
|
||||
if (c == 0) break;
|
||||
if (c < 0) {
|
||||
if (fptr_wait_readable(fptr))
|
||||
goto again;
|
||||
return -1;
|
||||
}
|
||||
offset += c;
|
||||
if ((n -= c) <= 0) break;
|
||||
}
|
||||
return len - n;
|
||||
return -1;
|
||||
}
|
||||
offset += c;
|
||||
if ((n -= c) <= 0) break;
|
||||
}
|
||||
return len - n;
|
||||
}
|
||||
|
||||
while (n > 0) {
|
||||
c = read_buffered_data(ptr+offset, n, fptr);
|
||||
if (c > 0) {
|
||||
offset += c;
|
||||
if ((n -= c) <= 0) break;
|
||||
}
|
||||
rb_io_check_closed(fptr);
|
||||
if (io_fillbuf(fptr) < 0) {
|
||||
break;
|
||||
}
|
||||
c = read_buffered_data(ptr+offset, n, fptr);
|
||||
if (c > 0) {
|
||||
offset += c;
|
||||
if ((n -= c) <= 0) break;
|
||||
}
|
||||
rb_io_check_closed(fptr);
|
||||
if (io_fillbuf(fptr) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return len - n;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue