about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-05-09 13:28:19 -0700
committerEric Wong <normalperson@yhbt.net>2011-05-09 13:34:31 -0700
commit4cbd3c3ea9e251eadd74e0971b0510fc05f95aa4 (patch)
tree444ba0c4f1ec331caf80ba8481340ebe4b709b9f
parent184f664d0773ea41c56b9db8dcf69878b9713855 (diff)
downloadruby_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.c50
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");
                 }