about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--ext/io_splice/io_splice_ext.c26
-rw-r--r--test/test_io_splice_eintr.rb34
2 files changed, 42 insertions, 18 deletions
diff --git a/ext/io_splice/io_splice_ext.c b/ext/io_splice/io_splice_ext.c
index a0ba381..eab1333 100644
--- a/ext/io_splice/io_splice_ext.c
+++ b/ext/io_splice/io_splice_ext.c
@@ -92,22 +92,12 @@ rb_thread_blocking_region(
 
 static VALUE io_run(rb_blocking_function_t *fn, void *data)
 {
-        return rb_thread_blocking_region(fn, data, RUBY_UBF_IO, 0);
-}
-
-/*
- * Releases GVL only iff blocking I/O is used.
- * Only use this if all file descriptors in data are pipes.
- * We'll trust programmers who use non-blocking I/O explicitly to
- * want the fastest possible performance without resorting to threads,
- * so releasing and them immediately reacquiring the GVL would be
- * a waste of time.
- */
-static VALUE nb_io_run(rb_blocking_function_t *fn, void *data, unsigned flags)
-{
-        if (flags & SPLICE_F_NONBLOCK)
-                return fn(data);
-        return io_run(fn, 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;
 }
 
 struct splice_args {
@@ -252,7 +242,7 @@ static long do_tee(int argc, VALUE *argv, unsigned dflags)
         a.len = (size_t)NUM2ULONG(len);
         a.flags = NIL_P(flags) ? dflags : NUM2UINT(flags) | dflags;
 
-        return (long)nb_io_run(nogvl_tee, &a, a.flags);
+        return (long)io_run(nogvl_tee, &a);
 }
 
 /*
@@ -437,7 +427,7 @@ static VALUE my_vmsplice(int argc, VALUE * argv, VALUE self)
         a.flags = NIL_P(flags) ? 0 : NUM2UINT(flags);
 
         for (;;) {
-                long n = (long)nb_io_run(nogvl_vmsplice, &a, a.flags);
+                long n = (long)io_run(nogvl_vmsplice, &a);
 
                 if (n < 0) {
                         if (errno == EAGAIN) {
diff --git a/test/test_io_splice_eintr.rb b/test/test_io_splice_eintr.rb
new file mode 100644
index 0000000..05926c9
--- /dev/null
+++ b/test/test_io_splice_eintr.rb
@@ -0,0 +1,34 @@
+# -*- encoding: binary -*-
+require 'test/unit'
+require 'tempfile'
+require 'socket'
+require 'io/nonblock'
+require 'timeout'
+$-w = true
+require 'io/splice'
+Thread.abort_on_exception = true
+
+class Test_IO_Splice_EINTR < Test::Unit::TestCase
+  def setup
+    @usr1 = 0
+    trap(:USR1) { @usr1 += 1 }
+  end
+
+  def teardown
+    trap(:USR1, "DEFAULT")
+  end
+
+  def test_EINTR_splice_read
+    rd, wr = IO.pipe
+    tmp = Tempfile.new 'splice-read'
+    main = Thread.current
+    Thread.new do
+      Thread.pass until main.stop?
+      Process.kill(:USR1, $$)
+      sleep 0.01
+      wr.write "HI"
+    end
+    nr = IO.splice rd, nil, tmp, nil, 666
+    assert_equal 2, nr
+  end
+end