summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
authorSamuel Williams <samuel.williams@oriontransfer.co.nz>2021-07-02 22:41:16 +1200
committerSamuel Williams <samuel.williams@oriontransfer.co.nz>2021-11-10 19:21:05 +1300
commit4b8903421828cb9d4de139180563ae8d8f04e1ab (patch)
tree21a0d02ba22afad6a4ce1c042acf6d74767dc5a2 /io.c
parent56b90cf94465ce347a3d9a779363c78ce3deb180 (diff)
IO::Buffer for scheduler interface.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4621
Diffstat (limited to 'io.c')
-rw-r--r--io.c358
1 files changed, 201 insertions, 157 deletions
diff --git a/io.c b/io.c
index ac7c7593af..81f7d8ecb6 100644
--- a/io.c
+++ b/io.c
@@ -14,6 +14,7 @@
#include "ruby/internal/config.h"
#include "ruby/fiber/scheduler.h"
+#include "ruby/io/buffer.h"
#ifdef _WIN32
# include "ruby/ruby.h"
@@ -131,6 +132,7 @@
#include "internal/transcode.h"
#include "internal/variable.h"
#include "ruby/io.h"
+#include "ruby/io/buffer.h"
#include "ruby/thread.h"
#include "ruby/util.h"
#include "ruby_atomic.h"
@@ -203,7 +205,7 @@ VALUE rb_default_rs;
static VALUE argf;
-static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding;
+static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
static VALUE sym_textmode, sym_binmode, sym_autoclose;
static VALUE sym_SET, sym_CUR, sym_END;
@@ -1060,7 +1062,7 @@ io_alloc(VALUE klass)
struct io_internal_read_struct {
VALUE th;
- int fd;
+ rb_io_t *fptr;
int nonblock;
void *buf;
size_t capa;
@@ -1080,18 +1082,18 @@ struct io_internal_writev_struct {
};
#endif
-static int nogvl_wait_for_single_fd(VALUE th, int fd, short events);
+static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events);
static VALUE
internal_read_func(void *ptr)
{
struct io_internal_read_struct *iis = ptr;
ssize_t r;
retry:
- r = read(iis->fd, iis->buf, iis->capa);
+ r = read(iis->fptr->fd, iis->buf, iis->capa);
if (r < 0 && !iis->nonblock) {
int e = errno;
if (io_again_p(e)) {
- if (nogvl_wait_for_single_fd(iis->th, iis->fd, RB_WAITFD_IN) != -1) {
+ if (nogvl_wait_for(iis->th, iis->fptr, RB_WAITFD_IN) != -1) {
goto retry;
}
errno = e;
@@ -1132,36 +1134,62 @@ internal_writev_func(void *ptr)
#endif
static ssize_t
-rb_read_internal(int fd, void *buf, size_t count)
+rb_read_internal(rb_io_t *fptr, void *buf, size_t count)
{
+ VALUE scheduler = rb_fiber_scheduler_current();
+ if (scheduler != Qnil) {
+ VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 1);
+
+ if (result != Qundef) {
+ ssize_t length = RB_NUM2SSIZE(result);
+
+ if (length < 0) rb_sys_fail_path(fptr->pathv);
+
+ return length;
+ }
+ }
+
struct io_internal_read_struct iis = {
.th = rb_thread_current(),
- .fd = fd,
+ .fptr = fptr,
.nonblock = 0,
.buf = buf,
.capa = count
};
- return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fd);
+ return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->fd);
}
static ssize_t
-rb_write_internal(int fd, const void *buf, size_t count)
+rb_write_internal(rb_io_t *fptr, const void *buf, size_t count)
{
+ VALUE scheduler = rb_fiber_scheduler_current();
+ if (scheduler != Qnil) {
+ VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, count);
+
+ if (result != Qundef) {
+ ssize_t length = RB_NUM2SSIZE(result);
+
+ if (length < 0) rb_sys_fail_path(fptr->pathv);
+
+ return length;
+ }
+ }
+
struct io_internal_write_struct iis = {
- .fd = fd,
+ .fd = fptr->fd,
.buf = buf,
.capa = count
};
- return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fd);
+ return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->fd);
}
static ssize_t
-rb_write_internal2(int fd, const void *buf, size_t count)
+rb_write_internal2(rb_io_t *fptr, const void *buf, size_t count)
{
struct io_internal_write_struct iis = {
- .fd = fd,
+ .fd = fptr->fd,
.buf = buf,
.capa = count
};
@@ -1581,7 +1609,7 @@ io_binwrite_string(VALUE arg)
}
}
else {
- r = rb_write_internal(fptr->fd, p->ptr, p->length);
+ r = rb_write_internal(fptr, p->ptr, p->length);
}
return r;
@@ -1612,7 +1640,7 @@ io_binwrite_string(VALUE arg)
return len;
}
- return rb_write_internal(p->fptr->fd, p->ptr, p->length);
+ return rb_write_internal(p->fptr, p->ptr, p->length);
}
#endif
@@ -1628,7 +1656,7 @@ io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
- VALUE result = rb_fiber_scheduler_io_write(scheduler, fptr->self, str, offset, len);
+ VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, ptr, len, len);
if (result != Qundef) {
ssize_t length = RB_NUM2SSIZE(result);
@@ -2316,27 +2344,26 @@ io_fillbuf(rb_io_t *fptr)
fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
#ifdef _WIN32
- fptr->rbuf.capa--;
+ fptr->rbuf.capa--;
#endif
}
if (fptr->rbuf.len == 0) {
retry:
- {
- r = rb_read_internal(fptr->fd, fptr->rbuf.ptr, fptr->rbuf.capa);
- }
+ r = rb_read_internal(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
+
if (r < 0) {
if (fptr_wait_readable(fptr))
goto retry;
- {
- int e = errno;
- VALUE path = rb_sprintf("fd:%d ", fptr->fd);
- if (!NIL_P(fptr->pathv)) {
- rb_str_append(path, fptr->pathv);
- }
- rb_syserr_fail_path(e, path);
- }
+
+ int e = errno;
+ VALUE path = rb_sprintf("fd:%d ", fptr->fd);
+ if (!NIL_P(fptr->pathv)) {
+ rb_str_append(path, fptr->pathv);
+ }
+
+ rb_syserr_fail_path(e, path);
}
- if (r > 0) rb_io_check_closed(fptr);
+ if (r > 0) rb_io_check_closed(fptr);
fptr->rbuf.off = 0;
fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
if (r == 0)
@@ -2557,6 +2584,16 @@ rb_io_fileno(VALUE io)
return INT2FIX(fd);
}
+int rb_io_descriptor(VALUE io)
+{
+ if (RB_TYPE_P(io, T_FILE)) {
+ rb_io_t *fptr = RFILE(io)->fptr;
+ rb_io_check_closed(fptr);
+ return fptr->fd;
+ } else {
+ return RB_NUM2INT(rb_funcall(io, id_fileno, 0));
+ }
+}
/*
* call-seq:
@@ -2665,7 +2702,7 @@ io_bufread(char *ptr, long len, rb_io_t *fptr)
while (n > 0) {
again:
rb_io_check_closed(fptr);
- c = rb_read_internal(fptr->fd, ptr+offset, n);
+ c = rb_read_internal(fptr, ptr+offset, n);
if (c == 0) break;
if (c < 0) {
if (fptr_wait_readable(fptr))
@@ -2711,19 +2748,6 @@ bufread_call(VALUE arg)
static long
io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
{
- VALUE scheduler = rb_fiber_scheduler_current();
- if (scheduler != Qnil) {
- VALUE result = rb_fiber_scheduler_io_read(scheduler, fptr->self, str, offset, size);
-
- if (result != Qundef) {
- ssize_t length = RB_NUM2SSIZE(result);
-
- if (length < 0) rb_sys_fail_path(fptr->pathv);
-
- return length;
- }
- }
-
long len;
struct bufread_arg arg;
@@ -3035,7 +3059,16 @@ read_internal_call(VALUE arg)
{
struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
- return rb_thread_io_blocking_region(internal_read_func, iis, iis->fd);
+ VALUE scheduler = rb_fiber_scheduler_current();
+ if (scheduler != Qnil) {
+ VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 1);
+
+ if (result != Qundef) {
+ return (VALUE)RB_NUM2SSIZE(result);
+ }
+ }
+
+ return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->fd);
}
static long
@@ -3079,7 +3112,7 @@ io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
}
io_setstrbuf(&str, len);
iis.th = rb_thread_current();
- iis.fd = fptr->fd;
+ iis.fptr = fptr;
iis.nonblock = nonblock;
iis.buf = RSTRING_PTR(str);
iis.capa = len;
@@ -3217,7 +3250,7 @@ io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str,
if (n <= 0) {
rb_io_set_nonblock(fptr);
shrinkable |= io_setstrbuf(&str, len);
- iis.fd = fptr->fd;
+ iis.fptr = fptr;
iis.nonblock = 1;
iis.buf = RSTRING_PTR(str);
iis.capa = len;
@@ -4726,10 +4759,10 @@ finish_writeconv(rb_io_t *fptr, int noalloc)
res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
while (dp-ds) {
retry:
- if (fptr->write_lock && rb_mutex_owned_p(fptr->write_lock))
- r = rb_write_internal2(fptr->fd, ds, dp-ds);
- else
- r = rb_write_internal(fptr->fd, ds, dp-ds);
+ if (fptr->write_lock && rb_mutex_owned_p(fptr->write_lock))
+ r = rb_write_internal2(fptr, ds, dp-ds);
+ else
+ r = rb_write_internal(fptr, ds, dp-ds);
if (r == dp-ds)
break;
if (0 <= r) {
@@ -4796,7 +4829,7 @@ static int
maygvl_close(int fd, int keepgvl)
{
if (keepgvl)
- return close(fd);
+ return close(fd);
/*
* close() may block for certain file types (NFS, SO_LINGER sockets,
@@ -4817,7 +4850,7 @@ static int
maygvl_fclose(FILE *file, int keepgvl)
{
if (keepgvl)
- return fclose(file);
+ return fclose(file);
return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
}
@@ -4835,64 +4868,77 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
int mode = fptr->mode;
if (fptr->writeconv) {
- if (fptr->write_lock && !noraise) {
+ if (fptr->write_lock && !noraise) {
struct finish_writeconv_arg arg;
arg.fptr = fptr;
arg.noalloc = noraise;
err = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
- }
- else {
- err = finish_writeconv(fptr, noraise);
- }
+ }
+ else {
+ err = finish_writeconv(fptr, noraise);
+ }
}
if (fptr->wbuf.len) {
- if (noraise) {
- io_flush_buffer_sync(fptr);
- }
- else {
- if (io_fflush(fptr) < 0 && NIL_P(err))
- err = INT2NUM(errno);
- }
+ if (noraise) {
+ io_flush_buffer_sync(fptr);
+ }
+ else {
+ if (io_fflush(fptr) < 0 && NIL_P(err))
+ err = INT2NUM(errno);
+ }
+ }
+
+ int done = 0;
+
+ if (IS_PREP_STDIO(fptr) || fd <= 2) {
+ // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
+ done = 1;
}
fptr->fd = -1;
fptr->stdio_file = 0;
fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
- /*
- * ensure waiting_fd users do not hit EBADF, wait for them
- * to exit before we call close().
- */
+ // Ensure waiting_fd users do not hit EBADF.
if (busy) {
+ // Wait for them to exit before we call close().
do rb_thread_schedule(); while (!list_empty(busy));
}
- if (IS_PREP_STDIO(fptr) || fd <= 2) {
- /* need to keep FILE objects of stdin, stdout and stderr */
- }
- else if (stdio_file) {
- /* stdio_file is deallocated anyway
- * even if fclose failed. */
- if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(err))
- if (!noraise) err = INT2NUM(errno);
+ // Disable for now.
+ // if (!done && fd >= 0) {
+ // VALUE scheduler = rb_fiber_scheduler_current();
+ // if (scheduler != Qnil) {
+ // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
+ // if (result != Qundef) done = 1;
+ // }
+ // }
+
+ if (!done && stdio_file) {
+ // stdio_file is deallocated anyway even if fclose failed.
+ if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(err))
+ if (!noraise) err = INT2NUM(errno);
+
+ done = 1;
}
- else if (0 <= fd) {
- /* fptr->fd may be closed even if close fails.
- * POSIX doesn't specify it.
- * We assumes it is closed. */
- /**/
- keepgvl |= !(mode & FMODE_WRITABLE);
- keepgvl |= noraise;
- if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(err))
- if (!noraise) err = INT2NUM(errno);
+ if (!done && fd >= 0) {
+ // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
+ // We assumes it is closed.
+
+ keepgvl |= !(mode & FMODE_WRITABLE);
+ keepgvl |= noraise;
+ if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(err))
+ if (!noraise) err = INT2NUM(errno);
+
+ done = 1;
}
if (!NIL_P(err) && !noraise) {
- if (RB_INTEGER_TYPE_P(err))
- rb_syserr_fail_path(NUM2INT(err), fptr->pathv);
- else
- rb_exc_raise(err);
+ if (RB_INTEGER_TYPE_P(err))
+ rb_syserr_fail_path(NUM2INT(err), fptr->pathv);
+ else
+ rb_exc_raise(err);
}
}
@@ -5333,7 +5379,7 @@ rb_io_syswrite(VALUE io, VALUE str)
tmp = rb_str_tmp_frozen_acquire(str);
RSTRING_GETMEM(tmp, ptr, len);
- n = rb_write_internal(fptr->fd, ptr, len);
+ n = rb_write_internal(fptr, ptr, len);
if (n < 0) rb_sys_fail_path(fptr->pathv);
rb_str_tmp_frozen_release(str, tmp);
@@ -5385,7 +5431,7 @@ rb_io_sysread(int argc, VALUE *argv, VALUE io)
io_setstrbuf(&str, ilen);
iis.th = rb_thread_current();
- iis.fd = fptr->fd;
+ iis.fptr = fptr;
iis.nonblock = 0;
iis.buf = RSTRING_PTR(str);
iis.capa = ilen;
@@ -11141,8 +11187,8 @@ struct copy_stream_struct {
off_t copy_length; /* (off_t)-1 if not specified */
off_t src_offset; /* (off_t)-1 if not specified */
- int src_fd;
- int dst_fd;
+ rb_io_t *src_fptr;
+ rb_io_t *dst_fptr;
unsigned close_src : 1;
unsigned close_dst : 1;
int error_no;
@@ -11192,18 +11238,18 @@ maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
struct wait_for_single_fd {
VALUE scheduler;
- int fd;
+ rb_io_t *fptr;
short events;
VALUE result;
};
static void *
-rb_thread_fiber_scheduler_wait_for_single_fd(void * _args)
+rb_thread_fiber_scheduler_wait_for(void * _args)
{
struct wait_for_single_fd *args = (struct wait_for_single_fd *)_args;
- args->result = rb_fiber_scheduler_io_wait(args->scheduler, io_from_fd(args->fd), INT2NUM(args->events), Qnil);
+ args->result = rb_fiber_scheduler_io_wait(args->scheduler, args->fptr->self, INT2NUM(args->events), Qnil);
return NULL;
}
@@ -11213,18 +11259,18 @@ rb_thread_fiber_scheduler_wait_for_single_fd(void * _args)
STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
static int
-nogvl_wait_for_single_fd(VALUE th, int fd, short events)
+nogvl_wait_for(VALUE th, rb_io_t *fptr, short events)
{
VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
if (scheduler != Qnil) {
- struct wait_for_single_fd args = {.scheduler = scheduler, .fd = fd, .events = events};
- rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for_single_fd, &args);
+ struct wait_for_single_fd args = {.scheduler = scheduler, .fptr = fptr, .events = events};
+ rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for, &args);
return RTEST(args.result);
}
struct pollfd fds;
- fds.fd = fd;
+ fds.fd = fptr->fd;
fds.events = events;
return poll(&fds, 1, -1);
@@ -11232,12 +11278,12 @@ nogvl_wait_for_single_fd(VALUE th, int fd, short events)
#else /* !USE_POLL */
# define IOWAIT_SYSCALL "select"
static int
-nogvl_wait_for_single_fd(VALUE th, int fd, short events)
+nogvl_wait_for(VALUE th, rb_io_t *fptr, short events)
{
VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
if (scheduler != Qnil) {
- struct wait_for_single_fd args = {.scheduler = scheduler, .fd = fd, .events = events};
- rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for_single_fd, &args);
+ struct wait_for_single_fd args = {.scheduler = scheduler, .fptr = fptr, .events = events};
+ rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for, &args);
return RTEST(args.result);
}
@@ -11245,17 +11291,17 @@ nogvl_wait_for_single_fd(VALUE th, int fd, short events)
int ret;
rb_fd_init(&fds);
- rb_fd_set(fd, &fds);
+ rb_fd_set(fptr->fd, &fds);
switch (events) {
case RB_WAITFD_IN:
- ret = rb_fd_select(fd + 1, &fds, 0, 0, 0);
+ ret = rb_fd_select(fptr->fd + 1, &fds, 0, 0, 0);
break;
case RB_WAITFD_OUT:
- ret = rb_fd_select(fd + 1, 0, &fds, 0, 0);
+ ret = rb_fd_select(fptr->fd + 1, 0, &fds, 0, 0);
break;
default:
- VM_UNREACHABLE(nogvl_wait_for_single_fd);
+ VM_UNREACHABLE(nogvl_wait_for);
}
rb_fd_term(&fds);
@@ -11273,7 +11319,7 @@ maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
ret = RB_NUM2INT(rb_io_wait(stp->src, RB_INT2NUM(RUBY_IO_READABLE), Qnil));
}
else {
- ret = nogvl_wait_for_single_fd(stp->th, stp->src_fd, RB_WAITFD_IN);
+ ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN);
}
} while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
@@ -11291,7 +11337,7 @@ nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
int ret;
do {
- ret = nogvl_wait_for_single_fd(stp->th, stp->dst_fd, RB_WAITFD_OUT);
+ ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT);
} while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
if (ret < 0) {
@@ -11338,7 +11384,7 @@ nogvl_copy_file_range(struct copy_stream_struct *stp)
if (src_offset < (off_t)0) {
off_t current_offset;
errno = 0;
- current_offset = lseek(stp->src_fd, 0, SEEK_CUR);
+ current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
if (current_offset < (off_t)0 && errno) {
stp->syserr = "lseek";
stp->error_no = errno;
@@ -11358,7 +11404,7 @@ nogvl_copy_file_range(struct copy_stream_struct *stp)
# else
ss = (ssize_t)copy_length;
# endif
- ss = simple_copy_file_range(stp->src_fd, src_offset_ptr, stp->dst_fd, NULL, ss, 0);
+ ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
if (0 < ss) {
stp->total += ss;
copy_length -= ss;
@@ -11393,7 +11439,7 @@ nogvl_copy_file_range(struct copy_stream_struct *stp)
case EBADF:
{
int e = errno;
- int flags = fcntl(stp->dst_fd, F_GETFL);
+ int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
if (flags != -1 && flags & O_APPEND) {
return 0;
@@ -11427,7 +11473,7 @@ nogvl_fcopyfile(struct copy_stream_struct *stp)
if (!S_ISREG(stp->dst_stat.st_mode))
return 0;
- if (lseek(stp->dst_fd, 0, SEEK_CUR) > (off_t)0) /* if dst IO was already written */
+ if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (off_t)0) /* if dst IO was already written */
return 0;
if (src_offset > (off_t)0) {
@@ -11435,14 +11481,14 @@ nogvl_fcopyfile(struct copy_stream_struct *stp)
/* get current offset */
errno = 0;
- cur = lseek(stp->src_fd, 0, SEEK_CUR);
+ cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
if (cur < (off_t)0 && errno) {
stp->error_no = errno;
return 1;
}
errno = 0;
- r = lseek(stp->src_fd, src_offset, SEEK_SET);
+ r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
if (r < (off_t)0 && errno) {
stp->error_no = errno;
return 1;
@@ -11450,7 +11496,7 @@ nogvl_fcopyfile(struct copy_stream_struct *stp)
}
stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
- ret = fcopyfile(stp->src_fd, stp->dst_fd, stp->copyfile_state, COPYFILE_DATA);
+ ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
if (ret == 0) { /* success */
@@ -11459,7 +11505,7 @@ nogvl_fcopyfile(struct copy_stream_struct *stp)
off_t r;
errno = 0;
/* reset offset */
- r = lseek(stp->src_fd, cur, SEEK_SET);
+ r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
if (r < (off_t)0 && errno) {
stp->error_no = errno;
return 1;
@@ -11557,7 +11603,7 @@ nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
else {
off_t cur;
errno = 0;
- cur = lseek(stp->src_fd, 0, SEEK_CUR);
+ cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
if (cur < (off_t)0 && errno) {
stp->syserr = "lseek";
stp->error_no = errno;
@@ -11575,10 +11621,10 @@ nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
ss = (ssize_t)copy_length;
# endif
if (use_pread) {
- ss = simple_sendfile(stp->dst_fd, stp->src_fd, &src_offset, ss);
+ ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
}
else {
- ss = simple_sendfile(stp->dst_fd, stp->src_fd, NULL, ss);
+ ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
}
if (0 < ss) {
stp->total += ss;
@@ -11609,7 +11655,7 @@ nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
int ret;
#ifndef __linux__
/*
- * Linux requires stp->src_fd to be a mmap-able (regular) file,
+ * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
* select() reports regular files to always be "ready", so
* there is no need to select() on it.
* Other OSes may have the same limitation for sendfile() which
@@ -11632,12 +11678,12 @@ nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
#endif
static ssize_t
-maygvl_read(int has_gvl, int fd, void *buf, size_t count)
+maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
{
if (has_gvl)
- return rb_read_internal(fd, buf, count);
+ return rb_read_internal(fptr, buf, count);
else
- return read(fd, buf, count);
+ return read(fptr->fd, buf, count);
}
static ssize_t
@@ -11646,11 +11692,11 @@ maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf,
ssize_t ss;
retry_read:
if (offset < (off_t)0) {
- ss = maygvl_read(has_gvl, stp->src_fd, buf, len);
+ ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
}
else {
#ifdef HAVE_PREAD
- ss = pread(stp->src_fd, buf, len, offset);
+ ss = pread(stp->src_fptr->fd, buf, len, offset);
#else
stp->notimp = "pread";
return -1;
@@ -11690,7 +11736,7 @@ nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
ssize_t ss;
int off = 0;
while (len) {
- ss = write(stp->dst_fd, buf+off, len);
+ ss = write(stp->dst_fptr->fd, buf+off, len);
if (ss < 0) {
if (maygvl_copy_stream_continue_p(0, stp))
continue;
@@ -11730,7 +11776,7 @@ nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
if (use_pread && stp->close_src) {
off_t r;
errno = 0;
- r = lseek(stp->src_fd, src_offset, SEEK_SET);
+ r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
if (r < (off_t)0 && errno) {
stp->syserr = "lseek";
stp->error_no = errno;
@@ -11812,7 +11858,7 @@ copy_stream_fallback_body(VALUE arg)
off_t off = stp->src_offset;
ID read_method = id_readpartial;
- if (stp->src_fd < 0) {
+ if (!stp->src_fptr) {
if (!rb_respond_to(stp->src, read_method)) {
read_method = id_read;
}
@@ -11831,7 +11877,7 @@ copy_stream_fallback_body(VALUE arg)
}
l = buflen < rest ? buflen : (long)rest;
}
- if (stp->src_fd < 0) {
+ if (!stp->src_fptr) {
VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
if (read_method == id_read && NIL_P(rc))
@@ -11864,7 +11910,7 @@ copy_stream_fallback_body(VALUE arg)
static VALUE
copy_stream_fallback(struct copy_stream_struct *stp)
{
- if (stp->src_fd < 0 && stp->src_offset >= (off_t)0) {
+ if (!stp->src_fptr && stp->src_offset >= (off_t)0) {
rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
}
rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
@@ -11878,8 +11924,6 @@ copy_stream_body(VALUE arg)
{
struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
VALUE src_io = stp->src, dst_io = stp->dst;
- rb_io_t *src_fptr = 0, *dst_fptr = 0;
- int src_fd, dst_fd;
const int common_oflags = 0
#ifdef O_NOCTTY
| O_NOCTTY
@@ -11894,7 +11938,7 @@ copy_stream_body(VALUE arg)
!(RB_TYPE_P(src_io, T_FILE) ||
RB_TYPE_P(src_io, T_STRING) ||
rb_respond_to(src_io, rb_intern("to_path")))) {
- src_fd = -1;
+ stp->src_fptr = NULL;
}
else {
int stat_ret;
@@ -11911,24 +11955,22 @@ copy_stream_body(VALUE arg)
stp->src = src_io;
stp->close_src = 1;
}
- GetOpenFile(src_io, src_fptr);
- rb_io_check_byte_readable(src_fptr);
- src_fd = src_fptr->fd;
+ RB_IO_POINTER(src_io, stp->src_fptr);
+ rb_io_check_byte_readable(stp->src_fptr);
- stat_ret = fstat(src_fd, &stp->src_stat);
+ stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
if (stat_ret < 0) {
stp->syserr = "fstat";
stp->error_no = errno;
return Qnil;
}
}
- stp->src_fd = src_fd;
if (dst_io == argf ||
!(RB_TYPE_P(dst_io, T_FILE) ||
RB_TYPE_P(dst_io, T_STRING) ||
rb_respond_to(dst_io, rb_intern("to_path")))) {
- dst_fd = -1;
+ stp->dst_fptr = NULL;
}
else {
int stat_ret;
@@ -11950,38 +11992,36 @@ copy_stream_body(VALUE arg)
dst_io = GetWriteIO(dst_io);
stp->dst = dst_io;
}
- GetOpenFile(dst_io, dst_fptr);
- rb_io_check_writable(dst_fptr);
- dst_fd = dst_fptr->fd;
+ RB_IO_POINTER(dst_io, stp->dst_fptr);
+ rb_io_check_writable(stp->dst_fptr);
- stat_ret = fstat(dst_fd, &stp->dst_stat);
+ stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
if (stat_ret < 0) {
stp->syserr = "fstat";
stp->error_no = errno;
return Qnil;
}
}
- stp->dst_fd = dst_fd;
#ifdef O_BINARY
- if (src_fptr)
- SET_BINARY_MODE_WITH_SEEK_CUR(src_fptr);
+ if (stp->src_fptr)
+ SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
#endif
- if (dst_fptr)
- io_ascii8bit_binmode(dst_fptr);
+ if (stp->dst_fptr)
+ io_ascii8bit_binmode(stp->dst_fptr);
- if (stp->src_offset < (off_t)0 && src_fptr && src_fptr->rbuf.len) {
- size_t len = src_fptr->rbuf.len;
+ if (stp->src_offset < (off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
+ size_t len = stp->src_fptr->rbuf.len;
VALUE str;
if (stp->copy_length >= (off_t)0 && stp->copy_length < (off_t)len) {
len = (size_t)stp->copy_length;
}
str = rb_str_buf_new(len);
rb_str_resize(str,len);
- read_buffered_data(RSTRING_PTR(str), len, src_fptr);
- if (dst_fptr) { /* IO or filename */
- if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), dst_fptr, 0) < 0)
- rb_sys_fail_on_write(dst_fptr);
+ read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
+ if (stp->dst_fptr) { /* IO or filename */
+ if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
+ rb_sys_fail_on_write(stp->dst_fptr);
}
else /* others such as StringIO */
rb_io_write(dst_io, str);
@@ -11991,14 +12031,14 @@ copy_stream_body(VALUE arg)
stp->copy_length -= len;
}
- if (dst_fptr && io_fflush(dst_fptr) < 0) {
+ if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
rb_raise(rb_eIOError, "flush failed");
}
if (stp->copy_length == 0)
return Qnil;
- if (src_fd < 0 || dst_fd < 0) {
+ if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
return copy_stream_fallback(stp);
}
@@ -12077,6 +12117,9 @@ rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
st.src = src;
st.dst = dst;
+ st.src_fptr = NULL;
+ st.dst_fptr = NULL;
+
if (NIL_P(length))
st.copy_length = (off_t)-1;
else
@@ -13678,6 +13721,7 @@ Init_IO(void)
id_flush = rb_intern_const("flush");
id_readpartial = rb_intern_const("readpartial");
id_set_encoding = rb_intern_const("set_encoding");
+ id_fileno = rb_intern_const("fileno");
rb_define_global_function("syscall", rb_f_syscall, -1);