From 4cbd3c3ea9e251eadd74e0971b0510fc05f95aa4 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 9 May 2011 13:28:19 -0700 Subject: [PATCH] detect closed descriptors on EINTR 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... --- ext/io_splice/io_splice_ext.c | 50 ++++++++++++++++++++++++++++++------------- 1 file 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 @@ -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"); } -- 2.11.4.GIT