expand doc for non-blocking splice into a pipe
authorEric Wong <normalperson@yhbt.net>
Wed, 18 May 2011 00:12:48 +0000 (17 17:12 -0700)
committerEric Wong <normalperson@yhbt.net>
Wed, 18 May 2011 00:12:48 +0000 (17 17:12 -0700)
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
lib/io/splice.rb

index ffccef1..23cc34f 100644 (file)
@@ -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");
index 89fab92..4b666f8 100644 (file)
@@ -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