Introduce rb_io_blocking_region which takes struct rb_io argument. (#11795)

This does not change any actual behaviour, but provides a choke point for blocking IO operations.

* Update `IO::Buffer` to use `rb_io_blocking_region`.

* Update `File` to use `rb_io_blocking_region`.

* Update `IO` to use `rb_io_blocking_region`.
This commit is contained in:
Samuel Williams 2024-10-05 15:10:12 +13:00 committed by GitHub
parent e766cb3e57
commit c50298d7d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
Notes: git 2024-10-05 02:10:30 +00:00
Merged-By: ioquatix <samuel@codeotaku.com>
5 changed files with 69 additions and 46 deletions

View file

@ -8601,6 +8601,7 @@ io_buffer.$(OBJEXT): $(top_srcdir)/internal/bits.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/compilers.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/error.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/io.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/numeric.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/serial.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/static_assert.h

24
file.c
View file

@ -1145,14 +1145,14 @@ no_gvl_fstat(void *data)
}
static int
fstat_without_gvl(int fd, struct stat *st)
fstat_without_gvl(rb_io_t *fptr, struct stat *st)
{
no_gvl_stat_data data;
data.file.fd = fd;
data.file.fd = fptr->fd;
data.st = st;
return (int)(VALUE)rb_thread_io_blocking_region(no_gvl_fstat, &data, fd);
return (int)rb_io_blocking_region(fptr, no_gvl_fstat, &data);
}
static void *
@ -1224,12 +1224,12 @@ statx_without_gvl(const char *path, struct statx *stx, unsigned int mask)
}
static int
fstatx_without_gvl(int fd, struct statx *stx, unsigned int mask)
fstatx_without_gvl(rb_io_t *fptr, struct statx *stx, unsigned int mask)
{
no_gvl_statx_data data = {stx, fd, "", AT_EMPTY_PATH, mask};
no_gvl_statx_data data = {stx, fptr->fd, "", AT_EMPTY_PATH, mask};
/* call statx(2) with fd */
return (int)rb_thread_io_blocking_region(io_blocking_statx, &data, fd);
return (int)rb_io_blocking_region(fptr, io_blocking_statx, &data);
}
static int
@ -1242,7 +1242,7 @@ rb_statx(VALUE file, struct statx *stx, unsigned int mask)
if (!NIL_P(tmp)) {
rb_io_t *fptr;
GetOpenFile(tmp, fptr);
result = fstatx_without_gvl(fptr->fd, stx, mask);
result = fstatx_without_gvl(fptr, stx, mask);
file = tmp;
}
else {
@ -1283,7 +1283,7 @@ typedef struct statx statx_data;
#elif defined(HAVE_STAT_BIRTHTIME)
# define statx_without_gvl(path, st, mask) stat_without_gvl(path, st)
# define fstatx_without_gvl(fd, st, mask) fstat_without_gvl(fd, st)
# define fstatx_without_gvl(fptr, st, mask) fstat_without_gvl(fptr, st)
# define statx_birthtime(st, fname) stat_birthtime(st)
# define statx_has_birthtime(st) 1
# define rb_statx(file, st, mask) rb_stat(file, st)
@ -1303,7 +1303,7 @@ rb_stat(VALUE file, struct stat *st)
rb_io_t *fptr;
GetOpenFile(tmp, fptr);
result = fstat_without_gvl(fptr->fd, st);
result = fstat_without_gvl(fptr, st);
file = tmp;
}
else {
@ -2501,7 +2501,7 @@ rb_file_birthtime(VALUE obj)
statx_data st;
GetOpenFile(obj, fptr);
if (fstatx_without_gvl(fptr->fd, &st, STATX_BTIME) == -1) {
if (fstatx_without_gvl(fptr, &st, STATX_BTIME) == -1) {
rb_sys_fail_path(fptr->pathv);
}
return statx_birthtime(&st, fptr->pathv);
@ -5280,7 +5280,7 @@ rb_file_truncate(VALUE obj, VALUE len)
}
rb_io_flush_raw(obj, 0);
fa.fd = fptr->fd;
if ((int)rb_thread_io_blocking_region(nogvl_ftruncate, &fa, fa.fd) < 0) {
if ((int)rb_io_blocking_region(fptr, nogvl_ftruncate, &fa) < 0) {
rb_sys_fail_path(fptr->pathv);
}
return INT2FIX(0);
@ -5380,7 +5380,7 @@ rb_file_flock(VALUE obj, VALUE operation)
if (fptr->mode & FMODE_WRITABLE) {
rb_io_flush_raw(obj, 0);
}
while ((int)rb_thread_io_blocking_region(rb_thread_flock, op, fptr->fd) < 0) {
while ((int)rb_io_blocking_region(fptr, rb_thread_flock, op) < 0) {
int e = errno;
switch (e) {
case EAGAIN:

View file

@ -135,6 +135,9 @@ RUBY_SYMBOL_EXPORT_BEGIN
void rb_maygvl_fd_fix_cloexec(int fd);
int rb_gc_for_fd(int err);
void rb_write_error_str(VALUE mesg);
VALUE rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events);
VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument);
RUBY_SYMBOL_EXPORT_END
#endif /* INTERNAL_IO_H */

64
io.c
View file

@ -222,6 +222,17 @@ static VALUE sym_HOLE;
static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
VALUE
rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
{
return rb_thread_io_blocking_call(function, argument, io->fd, events);
}
VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
{
return rb_io_blocking_region_wait(io, function, argument, 0);
}
struct argf {
VALUE filename, current_file;
long last_lineno; /* $. */
@ -1298,7 +1309,7 @@ rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
iis.timeout = &timeout_storage;
}
return (ssize_t)rb_thread_io_blocking_call(internal_read_func, &iis, fptr->fd, RB_WAITFD_IN);
return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
}
static ssize_t
@ -1331,7 +1342,7 @@ rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
iis.timeout = &timeout_storage;
}
return (ssize_t)rb_thread_io_blocking_call(internal_write_func, &iis, fptr->fd, RB_WAITFD_OUT);
return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
}
#ifdef HAVE_WRITEV
@ -1368,7 +1379,7 @@ rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
iis.timeout = &timeout_storage;
}
return (ssize_t)rb_thread_io_blocking_call(internal_writev_func, &iis, fptr->fd, RB_WAITFD_OUT);
return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
}
#endif
@ -1398,7 +1409,7 @@ static VALUE
io_flush_buffer_async(VALUE arg)
{
rb_io_t *fptr = (rb_io_t *)arg;
return rb_thread_io_blocking_call(io_flush_buffer_sync, fptr, fptr->fd, RB_WAITFD_OUT);
return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
}
static inline int
@ -2788,8 +2799,10 @@ rb_io_fsync(VALUE io)
if (io_fflush(fptr) < 0)
rb_sys_fail_on_write(fptr);
if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
rb_sys_fail_path(fptr->pathv);
return INT2FIX(0);
}
#else
@ -2838,7 +2851,7 @@ rb_io_fdatasync(VALUE io)
if (io_fflush(fptr) < 0)
rb_sys_fail_on_write(fptr);
if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
return INT2FIX(0);
/* fall back */
@ -3423,10 +3436,10 @@ io_read_memory_call(VALUE arg)
}
if (iis->nonblock) {
return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, 0);
return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
}
else {
return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, RB_WAITFD_IN);
return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
}
}
@ -6099,7 +6112,7 @@ rb_io_sysread(int argc, VALUE *argv, VALUE io)
}
struct prdwr_internal_arg {
VALUE io;
struct rb_io *io;
int fd;
void *buf;
size_t count;
@ -6121,14 +6134,14 @@ pread_internal_call(VALUE _arg)
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
if (!UNDEF_P(result)) {
return rb_fiber_scheduler_io_result_apply(result);
}
}
return rb_thread_io_blocking_call(internal_pread_func, arg, arg->fd, RB_WAITFD_IN);
return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
}
/*
@ -6165,7 +6178,7 @@ rb_io_pread(int argc, VALUE *argv, VALUE io)
VALUE len, offset, str;
rb_io_t *fptr;
ssize_t n;
struct prdwr_internal_arg arg = {.io = io};
struct prdwr_internal_arg arg;
int shrinkable;
rb_scan_args(argc, argv, "21", &len, &offset, &str);
@ -6179,6 +6192,7 @@ rb_io_pread(int argc, VALUE *argv, VALUE io)
GetOpenFile(io, fptr);
rb_io_check_byte_readable(fptr);
arg.io = fptr;
arg.fd = fptr->fd;
rb_io_check_closed(fptr);
@ -6203,7 +6217,7 @@ internal_pwrite_func(void *_arg)
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
if (!UNDEF_P(result)) {
return rb_fiber_scheduler_io_result_apply(result);
@ -6244,7 +6258,7 @@ rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
{
rb_io_t *fptr;
ssize_t n;
struct prdwr_internal_arg arg = {.io = io};
struct prdwr_internal_arg arg;
VALUE tmp;
if (!RB_TYPE_P(str, T_STRING))
@ -6255,13 +6269,15 @@ rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
arg.io = fptr;
arg.fd = fptr->fd;
tmp = rb_str_tmp_frozen_acquire(str);
arg.buf = RSTRING_PTR(tmp);
arg.count = (size_t)RSTRING_LEN(tmp);
n = (ssize_t)rb_thread_io_blocking_call(internal_pwrite_func, &arg, fptr->fd, RB_WAITFD_OUT);
n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
if (n < 0) rb_sys_fail_path(fptr->pathv);
rb_str_tmp_frozen_release(str, tmp);
@ -10806,7 +10822,7 @@ do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
ias.offset = offset;
ias.len = len;
rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
if (rv && rv != ENOSYS) {
/* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
it returns the error code. */
@ -11099,16 +11115,16 @@ nogvl_ioctl(void *ptr)
}
static int
do_ioctl(int fd, ioctl_req_t cmd, long narg)
do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
{
int retval;
struct ioctl_arg arg;
arg.fd = fd;
arg.fd = io->fd;
arg.cmd = cmd;
arg.narg = narg;
retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
return retval;
}
@ -11371,7 +11387,7 @@ rb_ioctl(VALUE io, VALUE req, VALUE arg)
narg = setup_narg(cmd, &arg, ioctl_narg_len);
GetOpenFile(io, fptr);
retval = do_ioctl(fptr->fd, cmd, narg);
retval = do_ioctl(fptr, cmd, narg);
return finish_narg(retval, arg, fptr);
}
@ -11425,16 +11441,16 @@ nogvl_fcntl(void *ptr)
}
static int
do_fcntl(int fd, int cmd, long narg)
do_fcntl(struct rb_io *io, int cmd, long narg)
{
int retval;
struct fcntl_arg arg;
arg.fd = fd;
arg.fd = io->fd;
arg.cmd = cmd;
arg.narg = narg;
retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
if (retval != -1) {
switch (cmd) {
#if defined(F_DUPFD)
@ -11460,7 +11476,7 @@ rb_fcntl(VALUE io, VALUE req, VALUE arg)
narg = setup_narg(cmd, &arg, fcntl_narg_len);
GetOpenFile(io, fptr);
retval = do_fcntl(fptr->fd, cmd, narg);
retval = do_fcntl(fptr, cmd, narg);
return finish_narg(retval, arg, fptr);
}

View file

@ -6,7 +6,6 @@
**********************************************************************/
#include "ruby/io.h"
#include "ruby/io/buffer.h"
#include "ruby/fiber/scheduler.h"
@ -16,7 +15,7 @@
#include "internal/error.h"
#include "internal/numeric.h"
#include "internal/string.h"
#include "internal/thread.h"
#include "internal/io.h"
VALUE rb_cIOBuffer;
VALUE rb_eIOBufferLockedError;
@ -2656,10 +2655,10 @@ io_buffer_default_size(size_t page_size)
}
struct io_buffer_blocking_region_argument {
struct rb_io *io;
struct rb_io_buffer *buffer;
rb_blocking_function_t *function;
void *data;
int descriptor;
};
static VALUE
@ -2667,7 +2666,7 @@ io_buffer_blocking_region_begin(VALUE _argument)
{
struct io_buffer_blocking_region_argument *argument = (void*)_argument;
return rb_thread_io_blocking_region(argument->function, argument->data, argument->descriptor);
return rb_io_blocking_region(argument->io, argument->function, argument->data);
}
static VALUE
@ -2681,13 +2680,17 @@ io_buffer_blocking_region_ensure(VALUE _argument)
}
static VALUE
io_buffer_blocking_region(struct rb_io_buffer *buffer, rb_blocking_function_t *function, void *data, int descriptor)
io_buffer_blocking_region(VALUE io, struct rb_io_buffer *buffer, rb_blocking_function_t *function, void *data)
{
io = rb_io_get_io(io);
struct rb_io *ioptr;
RB_IO_POINTER(io, ioptr);
struct io_buffer_blocking_region_argument argument = {
.io = ioptr,
.buffer = buffer,
.function = function,
.data = data,
.descriptor = descriptor,
};
// If the buffer is already locked, we can skip the ensure (unlock):
@ -2774,7 +2777,7 @@ rb_io_buffer_read(VALUE self, VALUE io, size_t length, size_t offset)
.length = length,
};
return io_buffer_blocking_region(buffer, io_buffer_read_internal, &argument, descriptor);
return io_buffer_blocking_region(io, buffer, io_buffer_read_internal, &argument);
}
/*
@ -2892,7 +2895,7 @@ rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t of
.offset = from,
};
return io_buffer_blocking_region(buffer, io_buffer_pread_internal, &argument, descriptor);
return io_buffer_blocking_region(io, buffer, io_buffer_pread_internal, &argument);
}
/*
@ -3011,7 +3014,7 @@ rb_io_buffer_write(VALUE self, VALUE io, size_t length, size_t offset)
.length = length,
};
return io_buffer_blocking_region(buffer, io_buffer_write_internal, &argument, descriptor);
return io_buffer_blocking_region(io, buffer, io_buffer_write_internal, &argument);
}
/*
@ -3129,7 +3132,7 @@ rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t o
.offset = from,
};
return io_buffer_blocking_region(buffer, io_buffer_pwrite_internal, &argument, descriptor);
return io_buffer_blocking_region(io, buffer, io_buffer_pwrite_internal, &argument);
}
/*