diff options
author | Eric Wong <normalperson@yhbt.net> | 2011-05-09 13:28:19 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2011-05-09 13:34:31 -0700 |
commit | 4cbd3c3ea9e251eadd74e0971b0510fc05f95aa4 (patch) | |
tree | 444ba0c4f1ec331caf80ba8481340ebe4b709b9f | |
parent | 184f664d0773ea41c56b9db8dcf69878b9713855 (diff) | |
download | ruby_io_splice-4cbd3c3ea9e251eadd74e0971b0510fc05f95aa4.tar.gz |
We don't want to retry with the same FD if it somehow got closed and reopened in a different thread. We could possibly have Errno::EBADF, too, but rb_thread_io_blocking_region doesn't allow multiple file descriptors...
-rw-r--r-- | ext/io_splice/io_splice_ext.c | 50 |
1 files changed, 35 insertions, 15 deletions
diff --git a/ext/io_splice/io_splice_ext.c b/ext/io_splice/io_splice_ext.c index 4396fb0..1181797 100644 --- a/ext/io_splice/io_splice_ext.c +++ b/ext/io_splice/io_splice_ext.c @@ -54,6 +54,14 @@ static int my_fileno(VALUE io) } } } + +static int check_fileno(VALUE io) +{ + int saved_errno = errno; + int fd = my_fileno(io); + errno = saved_errno; + return fd; +} #ifndef HAVE_RB_THREAD_BLOCKING_REGION /* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */ # include <rubysig.h> @@ -92,12 +100,7 @@ rb_thread_blocking_region( static VALUE io_run(rb_blocking_function_t *fn, void *data) { - ssize_t n; -retry: - n = (ssize_t)rb_thread_blocking_region(fn, data, RUBY_UBF_IO, 0); - if (n == -1 && errno == EINTR) - goto retry; - return (VALUE)n; + return rb_thread_blocking_region(fn, data, RUBY_UBF_IO, 0); } struct splice_args { @@ -122,18 +125,23 @@ static long do_splice(int argc, VALUE *argv, unsigned dflags) off_t i, o; VALUE fd_in, off_in, fd_out, off_out, len, flags; struct splice_args a; + long bytes; rb_scan_args(argc, argv, "51", &fd_in, &off_in, &fd_out, &off_out, &len, &flags); a.off_in = NIL_P(off_in) ? NULL : (i = NUM2OFFT(off_in), &i); a.off_out = NIL_P(off_out) ? NULL : (o = NUM2OFFT(off_out), &o); - a.fd_in = my_fileno(fd_in); - a.fd_out = my_fileno(fd_out); a.len = (size_t)NUM2ULONG(len); a.flags = NIL_P(flags) ? dflags : NUM2UINT(flags) | dflags; - return (long)io_run(nogvl_splice, &a); + do { + a.fd_in = check_fileno(fd_in); + a.fd_out = check_fileno(fd_out); + bytes = (long)io_run(nogvl_splice, &a); + } while (bytes == -1 && errno == EINTR); + + return bytes; } /* @@ -235,14 +243,19 @@ static long do_tee(int argc, VALUE *argv, unsigned dflags) { VALUE fd_in, fd_out, len, flags; struct tee_args a; + long bytes; rb_scan_args(argc, argv, "31", &fd_in, &fd_out, &len, &flags); - a.fd_in = my_fileno(fd_in); - a.fd_out = my_fileno(fd_out); a.len = (size_t)NUM2ULONG(len); a.flags = NIL_P(flags) ? dflags : NUM2UINT(flags) | dflags; - return (long)io_run(nogvl_tee, &a); + do { + a.fd_in = check_fileno(fd_in); + a.fd_out = check_fileno(fd_out); + bytes = (long)io_run(nogvl_tee, &a); + } while (bytes == -1 && errno == EINTR); + + return bytes; } /* @@ -431,10 +444,13 @@ static VALUE my_vmsplice(int argc, VALUE * argv, VALUE self) if (n < 0) { if (errno == EAGAIN) { - if (a.flags & SPLICE_F_NONBLOCK) + if (a.flags & SPLICE_F_NONBLOCK) { rb_sys_fail("vmsplice"); - else if (rb_io_wait_writable(a.fd)) - continue; + } else { + a.fd = check_fileno(fd); + if (rb_io_wait_writable(a.fd)) + continue; + } /* fall through on error */ } /* @@ -444,6 +460,10 @@ static VALUE my_vmsplice(int argc, VALUE * argv, VALUE self) */ if (rv > 0) break; + if (errno == EINTR) { + a.fd = check_fileno(fd); + continue; + } rb_sys_fail("vmsplice"); } |