about summary refs log tree commit homepage
path: root/ext
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-08-02 07:40:48 +0000
committerEric Wong <normalperson@yhbt.net>2010-08-02 07:45:39 +0000
commita6a3ba543c3b9069437ade7741c694ce3da2e884 (patch)
tree0ae1d807f9f361e1c515b52786f13fcbcc6dbfb9 /ext
parentdcd710c622530052be50b226d245caebb6d2a970 (diff)
downloadruby_io_splice-a6a3ba543c3b9069437ade7741c694ce3da2e884.tar.gz
These are friendly wrappers around F_GETPIPE_SZ
and F_SETPIPE_SZ fcntl()s in Linux 2.6.35.
Diffstat (limited to 'ext')
-rw-r--r--ext/io_splice/io_splice_ext.c111
1 files changed, 102 insertions, 9 deletions
diff --git a/ext/io_splice/io_splice_ext.c b/ext/io_splice/io_splice_ext.c
index 32fe782..1d27522 100644
--- a/ext/io_splice/io_splice_ext.c
+++ b/ext/io_splice/io_splice_ext.c
@@ -10,6 +10,16 @@
 #include <sys/uio.h>
 #include <limits.h>
 #include <alloca.h>
+#include <sys/utsname.h>
+
+#ifndef F_LINUX_SPECIFIC_BASE
+#  define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_GETPIPE_SZ
+#  define F_SETPIPE_SZ    (F_LINUX_SPECIFIC_BASE + 7)
+#  define F_GETPIPE_SZ    (F_LINUX_SPECIFIC_BASE + 8)
+#endif
 
 #if ! HAVE_RB_IO_T
 #  define rb_io_t OpenFile
@@ -361,9 +371,76 @@ static VALUE my_vmsplice(VALUE self, VALUE fd, VALUE data, VALUE flags)
         return LONG2NUM(rv);
 }
 
+/*
+ * call-seq:
+ *   reader, writer = IO.pipe
+ *   reader.pipe_size => integer
+ *
+ * Returns the pipe capacity of the underlying pipe in bytes.  The
+ * default capacity is 65536 bytes since Linux 2.6.11, and 4096 bytes
+ * in previous kernels.
+ *
+ * Since the pipe is a circular buffer in the same kernel, the size
+ * of the reader is exactly the same as the size of the writer.
+ *
+ * This method is only exposed on Linux 2.6.35 or later.
+ */
+static VALUE pipe_size(VALUE self)
+{
+        int size = fcntl(my_fileno(self),  F_GETPIPE_SZ);
+
+        if (size < 0)
+                rb_sys_fail("fcntl(F_GETPIPE_SZ)");
+
+        return INT2NUM(size);
+}
+
+/*
+ * call-seq:
+ *   reader, writer = IO.pipe
+ *   reader.pipe_size = integer
+ *
+ * Sets and returns the pipe capacity of the underlying pipe in bytes.
+ *
+ * This MUST be a power-of-two, or Errno::EINVAL will be raised.
+ * Linux will silently increase this to be equal to the page size
+ * (4096 bytes on most architectures) if the specified value is
+ * less than the size of a page.
+ *
+ * For users without CAP_SYS_RESOURCE, this raises Errno::EPERM when
+ * attempting to specify a value greater than the value in
+ * /proc/sys/fs/pipe-max-size.
+ *
+ * Since the pipe is a circular buffer in the same kernel, the size
+ * of the reader is exactly the same as the size of the writer.
+ *
+ * Raises Errno::EBUSY if the assigned value is less than
+ * the currently filled portion of the pipe.
+ *
+ * This method is only exposed on Linux 2.6.35 or later.
+ */
+static VALUE set_pipe_size(VALUE self, VALUE size)
+{
+        int fd = my_fileno(self);
+        int bytes = NUM2INT(size);
+        int rv = fcntl(fd, F_SETPIPE_SZ, bytes);
+
+        if (rv < 0) {
+                if (errno == ENOMEM) {
+                        rb_gc();
+                        rv = fcntl(fd, F_SETPIPE_SZ, bytes);
+                }
+                if (rv < 0)
+                        rb_sys_fail("fcntl(F_SETPIPE_SZ)");
+        }
+
+        return size;
+}
+
 void Init_io_splice_ext(void)
 {
         VALUE mSplice = rb_define_module_under(rb_cIO, "Splice");
+        struct utsname utsname;
 
         rb_define_singleton_method(rb_cIO, "splice", my_splice, 6);
         rb_define_singleton_method(rb_cIO, "tee", my_tee, 4);
@@ -402,19 +479,35 @@ void Init_io_splice_ext(void)
          */
         rb_define_const(mSplice, "F_GIFT", UINT2NUM(SPLICE_F_GIFT));
 
-#ifdef F_GETPIPE_SZ
-        /* :nodoc: */
-        rb_define_const(mSplice, "F_GETPIPE_SZ", UINT2NUM(F_GETPIPE_SZ));
-#endif
-#ifdef F_SETPIPE_SZ
-        /* :nodoc: */
-        rb_define_const(mSplice, "F_SETPIPE_SZ", UINT2NUM(F_SETPIPE_SZ));
-#endif
-
         /*
          * The maximum size of an atomic write to a pipe
          * POSIX requires this to be at least 512 bytes.
          * Under Linux, this is 4096 bytes.
          */
         rb_define_const(mSplice, "PIPE_BUF", UINT2NUM(PIPE_BUF));
+
+        if (uname(&utsname) == -1)
+                rb_sys_fail("uname");
+
+        /* includes 2.6.35-rc[1-6] */
+        if (strcmp(utsname.release, "2.6.35") >= 0) {
+                rb_define_method(rb_cIO, "pipe_size", pipe_size, 0);
+                rb_define_method(rb_cIO, "pipe_size=", set_pipe_size, 1);
+
+                /*
+                 * fcntl() command constant used to return the size of a pipe.
+                 * This constant is only defined when running Linux 2.6.35
+                 * or later.  For convenience, use IO#pipe_size instead.
+                 */
+                rb_define_const(mSplice, "F_GETPIPE_SZ",
+                                UINT2NUM(F_GETPIPE_SZ));
+
+                /*
+                 * fcntl() command constant used to set the size of a pipe.
+                 * This constant is only defined when running Linux 2.6.35
+                 * or later.  For convenience, use IO#pipe_size= instead.
+                 */
+                rb_define_const(mSplice, "F_SETPIPE_SZ",
+                                UINT2NUM(F_SETPIPE_SZ));
+        }
 }