From a6a3ba543c3b9069437ade7741c694ce3da2e884 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 2 Aug 2010 07:40:48 +0000 Subject: add IO#pipe_size and IO#pipe_size= accessors These are friendly wrappers around F_GETPIPE_SZ and F_SETPIPE_SZ fcntl()s in Linux 2.6.35. --- ext/io_splice/io_splice_ext.c | 111 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 9 deletions(-) (limited to 'ext') 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 #include #include +#include + +#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)); + } } -- cgit v1.2.3-24-ge0c7