Skip to content

Commit

Permalink
Rework sysread to use blocking read_internal_locktmp.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Jun 22, 2021
1 parent 45e65f3 commit fcc6fd2
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 15 deletions.
18 changes: 6 additions & 12 deletions io.c
Expand Up @@ -5349,30 +5349,24 @@ rb_io_sysread(int argc, VALUE *argv, VALUE io)
rb_raise(rb_eIOError, "sysread for buffered IO");
}

/*
* FIXME: removing rb_thread_wait_fd() here changes sysread semantics
* on non-blocking IOs. However, it's still currently possible
* for sysread to raise Errno::EAGAIN if another thread read()s
* the IO after we return from rb_thread_wait_fd() but before
* we call read()
*/
rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil);

rb_io_check_closed(fptr);

io_setstrbuf(&str, ilen);
iis.th = rb_thread_current();
iis.fd = fptr->fd;
iis.nonblock = 1; /* for historical reasons, maybe (see above) */
iis.nonblock = 0;
iis.buf = RSTRING_PTR(str);
iis.capa = ilen;
n = read_internal_locktmp(str, &iis);

if (n < 0) {
rb_sys_fail_path(fptr->pathv);
rb_sys_fail_path(fptr->pathv);
}

io_set_read_length(str, n, shrinkable);

if (n == 0 && ilen > 0) {
rb_eof_error();
rb_eof_error();
}

return str;
Expand Down
12 changes: 9 additions & 3 deletions test/ruby/test_io.rb
Expand Up @@ -3316,11 +3316,17 @@ def test_sysread_locktmp
data = "a" * 100
with_pipe do |r,w|
th = Thread.new {r.sysread(100, buf)}

Thread.pass until th.stop?
buf.replace("")
assert_empty(buf, bug6099)

assert_equal 100, buf.bytesize

msg = /can't modify string; temporarily locked/
assert_raise_with_message(RuntimeError, msg) do
buf.replace("")
end
assert_predicate(th, :alive?)
w.write(data)
Thread.pass while th.alive?
th.join
end
assert_equal(data, buf, bug6099)
Expand Down

0 comments on commit fcc6fd2

Please sign in to comment.