diff options
-rw-r--r-- | ext/io_splice/io_splice_ext.c | 26 | ||||
-rw-r--r-- | test/test_io_splice_eintr.rb | 34 |
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 |