From 1e4b4af9d8fa01b59b933fe94b405288f668a7fc Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 17 May 2011 17:12:48 -0700 Subject: [PATCH] expand doc for non-blocking splice into a pipe We should warn our users to avoid a blocking splice() from a socket into a pipe if the socket buffers are full unless there's a blocking read/splice on the other end of the pipe. --- ext/io_splice/io_splice_ext.c | 14 +++++++++++--- lib/io/splice.rb | 7 +++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/ext/io_splice/io_splice_ext.c b/ext/io_splice/io_splice_ext.c index ffccef1..23cc34f 100644 --- a/ext/io_splice/io_splice_ext.c +++ b/ext/io_splice/io_splice_ext.c @@ -217,9 +217,9 @@ static ssize_t do_splice(int argc, VALUE *argv, unsigned dflags) * into account userspace buffering done by Ruby or stdio. It is * also not subject to encoding/decoding filters under Ruby 1.9. * - * Consider using IO.trysplice if you are using non-blocking I/O on - * both descriptors as it avoids the cost of raising common Errno::EAGAIN - * exceptions. + * Consider using IO.trysplice if +io_out+ is a pipe or if you are using + * non-blocking I/O on both descriptors as it avoids the cost of raising + * common Errno::EAGAIN exceptions. * * See manpage for full documentation: * http://kernel.org/doc/man-pages/online/pages/man2/splice.2.html @@ -247,6 +247,8 @@ static VALUE my_splice(int argc, VALUE *argv, VALUE self) * but this can still block if the non-pipe descriptor is blocking. * * See IO.splice documentation for more details. + * + * This method is recommended whenever +io_out+ is a pipe. */ static VALUE trysplice(int argc, VALUE *argv, VALUE self) { @@ -639,6 +641,12 @@ void Init_io_splice_ext(void) * themselves are ignored by this family of functions, and * using this flag is the only way to get non-blocking operation * out of them. + * + * It is highly recommended this flag be set (or IO.trysplice used) + * whenever splicing from a socket into a pipe unless there is + * another (native) thread or process doing a blocking read on that + * pipe. Otherwise it is possible to block a single-threaded process + * if the socket buffers are larger than the pipe buffers. */ rb_define_const(mSplice, "F_NONBLOCK", UINT2NUM(SPLICE_F_NONBLOCK)); assert(WAITALL != SPLICE_F_NONBLOCK && "WAITALL == F_NONBLOCK"); diff --git a/lib/io/splice.rb b/lib/io/splice.rb index 89fab92..4b666f8 100644 --- a/lib/io/splice.rb +++ b/lib/io/splice.rb @@ -84,6 +84,13 @@ module IO::Splice # This will block and wait for IO completion of +len+ # Raises +EOFError+ if end of file is reached. # bytes. Returns the number of bytes actually spliced (always +len+) + # unless +src+ does not have +len+ bytes to read. + # + # Do not use this method to splice a socket +src+ into a pipe +dst+ + # unless there is another process or native thread doing a blocking + # read on the other end of the +dst+ pipe. + # + # This method is safe for splicing a pipe +src+ into any type of +dst+ IO. def self.full(src, dst, len, src_offset) IO.splice(src, src_offset, dst, nil, len, F_MOVE | WAITALL) end -- 2.11.4.GIT