80c8cdef880c8ba87ed346fe2f515e53840e000b
[ruby_io_splice.git] / ext / io_splice / io_splice_ext.c
blob80c8cdef880c8ba87ed346fe2f515e53840e000b
1 #include "ruby.h"
2 #ifdef HAVE_RUBY_IO_H
3 # include "ruby/io.h"
4 #else
5 # include "rubyio.h"
6 #endif
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <assert.h>
10 #include <sys/uio.h>
11 #include <limits.h>
12 #include <alloca.h>
13 #include <sys/utsname.h>
15 static VALUE sym_EAGAIN;
16 #define WAITALL 0x4000000
18 #ifndef F_LINUX_SPECIFIC_BASE
19 # define F_LINUX_SPECIFIC_BASE 1024
20 #endif
22 #ifndef F_GETPIPE_SZ
23 # define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
24 # define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
25 #endif
27 #if ! HAVE_RB_IO_T
28 # define rb_io_t OpenFile
29 #endif
31 #ifdef GetReadFile
32 # define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
33 #else
34 # if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
35 # define FPTR_TO_FD(fptr) fileno(fptr->f)
36 # else
37 # define FPTR_TO_FD(fptr) fptr->fd
38 # endif
39 #endif
41 #ifndef SSIZET2NUM
42 # define SSIZET2NUM(x) LONG2NUM(x)
43 #endif
44 #ifndef NUM2SSIZET
45 # define NUM2SSIZET(x) NUM2LONG(x)
46 #endif
47 #ifndef SIZET2NUM
48 # define SIZET2NUM(x) ULONG2NUM(x)
49 #endif
50 #ifndef NUM2SIZET
51 # define NUM2SIZET(x) NUM2ULONG(x)
52 #endif
54 static int my_fileno(VALUE io)
56 rb_io_t *fptr;
58 for (;;) {
59 switch (TYPE(io)) {
60 case T_FIXNUM: return FIX2INT(io);
61 case T_FILE: {
62 GetOpenFile(io, fptr);
63 return FPTR_TO_FD(fptr);
65 default:
66 io = rb_convert_type(io, T_FILE, "IO", "to_io");
67 /* retry */
72 static int check_fileno(VALUE io)
74 int saved_errno = errno;
75 int fd = my_fileno(io);
76 errno = saved_errno;
77 return fd;
79 #ifndef HAVE_RB_THREAD_BLOCKING_REGION
80 /* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
81 # include <rubysig.h>
82 # define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
83 typedef void rb_unblock_function_t(void *);
84 typedef VALUE rb_blocking_function_t(void *);
85 static VALUE
86 rb_thread_blocking_region(
87 rb_blocking_function_t *fn, void *data1,
88 rb_unblock_function_t *ubf, void *data2)
90 VALUE rv;
92 assert(RUBY_UBF_IO == ubf && "RUBY_UBF_IO required for emulation");
94 TRAP_BEG;
95 rv = fn(data1);
96 TRAP_END;
98 return rv;
100 #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
102 #ifndef RSTRING_PTR
103 # define RSTRING_PTR(s) (RSTRING(s)->ptr)
104 #endif
105 #ifndef RSTRING_LEN
106 # define RSTRING_LEN(s) (RSTRING(s)->len)
107 #endif
108 #ifndef RARRAY_PTR
109 # define RARRAY_PTR(s) (RARRAY(s)->ptr)
110 #endif
111 #ifndef RARRAY_LEN
112 # define RARRAY_LEN(s) (RARRAY(s)->len)
113 #endif
115 static VALUE io_run(rb_blocking_function_t *fn, void *data)
117 return rb_thread_blocking_region(fn, data, RUBY_UBF_IO, 0);
120 struct splice_args {
121 int fd_in;
122 off_t *off_in;
123 int fd_out;
124 off_t *off_out;
125 size_t len;
126 unsigned flags;
129 static VALUE nogvl_splice(void *ptr)
131 struct splice_args *a = ptr;
133 return (VALUE)splice(a->fd_in, a->off_in, a->fd_out, a->off_out,
134 a->len, a->flags);
137 static ssize_t do_splice(int argc, VALUE *argv, unsigned dflags)
139 off_t i = 0, o = 0;
140 VALUE fd_in, off_in, fd_out, off_out, len, flags;
141 struct splice_args a;
142 ssize_t bytes;
143 ssize_t total = 0;
144 unsigned waitall;
146 rb_scan_args(argc, argv, "51",
147 &fd_in, &off_in, &fd_out, &off_out, &len, &flags);
149 a.off_in = NIL_P(off_in) ? NULL : (i = NUM2OFFT(off_in), &i);
150 a.off_out = NIL_P(off_out) ? NULL : (o = NUM2OFFT(off_out), &o);
151 a.len = NUM2SIZET(len);
152 a.flags = NIL_P(flags) ? dflags : NUM2UINT(flags) | dflags;
153 waitall = a.flags & WAITALL;
154 if (waitall)
155 a.flags ^= WAITALL;
157 for (;;) {
158 a.fd_in = check_fileno(fd_in);
159 a.fd_out = check_fileno(fd_out);
160 bytes = (ssize_t)io_run(nogvl_splice, &a);
161 if (bytes == -1) {
162 if (errno == EINTR)
163 continue;
164 if (waitall && errno == EAGAIN) {
165 rb_io_wait_readable(check_fileno(fd_in));
166 errno = EAGAIN;
167 rb_io_wait_writable(check_fileno(fd_out));
168 continue;
170 if (total > 0)
171 return total;
172 return bytes;
173 } else if (bytes == 0) {
174 break;
175 } else if (waitall) {
176 total += bytes;
177 if ((a.len -= bytes) == 0)
178 return total;
179 i += bytes;
180 o += bytes;
181 } else {
182 return bytes;
186 return total;
190 * call-seq:
191 * IO.splice(fd_in, off_in, fd_out, off_out, len) => integer
192 * IO.splice(fd_in, off_in, fd_out, off_out, len, flags) => integer
194 * Splice +len+ bytes from/to a pipe. Either +fd_in+ or +fd_out+
195 * MUST be a pipe. +fd_in+ and +fd_out+ may BOTH be pipes as of
196 * Linux 2.6.31 or later.
198 * +off_in+ and +off_out+ if non-nil may be used to
199 * specify an offset for the non-pipe file descriptor.
201 * +flags+ defaults to zero if unspecified.
202 * +flags+ may be a bitmask of the following flags:
204 * IO::Splice::F_MOVE, IO::Splice::F_NONBLOCK, IO::Splice::F_MORE
206 * Returns the number of bytes spliced.
207 * Raises EOFError when +fd_in+ has reached end of file.
208 * Raises Errno::EAGAIN if the IO::Splice::F_NONBLOCK flag is set
209 * and the pipe has no data to read from or space to write to. May
210 * also raise Errno::EAGAIN if the non-pipe descriptor has no data
211 * to read from or space to write to.
213 * rd, wr = (pipe = IO.pipe).map { |io| io.fileno }
214 * src_io, dst_io = File.open("/path/to/src"), File.open("/path/to/dst")
215 * src, dst = src_io.fileno, dst_io.fileno
217 * nr = IO.splice(src, nil, wr, nil, IO::Splice::PIPE_CAPA, 0)
218 * IO.splice(rd, nil, dst, nil, nr, 0)
220 * As splice never exposes buffers to userspace, it will not take
221 * into account userspace buffering done by Ruby or stdio. It is
222 * also not subject to encoding/decoding filters under Ruby 1.9.
224 * Consider using IO.trysplice if you are using non-blocking I/O on
225 * both descriptors as it avoids the cost of raising common Errno::EAGAIN
226 * exceptions.
228 * See manpage for full documentation:
229 * http://kernel.org/doc/man-pages/online/pages/man2/splice.2.html
231 static VALUE my_splice(int argc, VALUE *argv, VALUE self)
233 ssize_t n = do_splice(argc, argv, 0);
235 if (n == 0)
236 rb_eof_error();
237 if (n == -1)
238 rb_sys_fail("splice");
239 return SSIZET2NUM(n);
243 * call-seq:
244 * IO.trysplice(fd_in, off_in, fd_out, off_out, len) => integer
245 * IO.trysplice(fd_in, off_in, fd_out, off_out, len, flags) => integer
247 * Exactly like IO.splice, except +:EAGAIN+ is returned when either
248 * the read or write end would block instead of raising Errno::EAGAIN.
250 * IO::Splice::F_NONBLOCK is always passed for the pipe descriptor,
251 * but this can still block if the non-pipe descriptor is blocking.
253 * See IO.splice documentation for more details.
255 static VALUE trysplice(int argc, VALUE *argv, VALUE self)
257 ssize_t n = do_splice(argc, argv, SPLICE_F_NONBLOCK);
259 if (n == 0)
260 return Qnil;
261 if (n == -1) {
262 if (errno == EAGAIN)
263 return sym_EAGAIN;
264 rb_sys_fail("splice");
266 return SSIZET2NUM(n);
269 struct tee_args {
270 int fd_in;
271 int fd_out;
272 size_t len;
273 unsigned flags;
276 /* runs without GVL */
277 static VALUE nogvl_tee(void *ptr)
279 struct tee_args *a = ptr;
281 return (VALUE)tee(a->fd_in, a->fd_out, a->len, a->flags);
284 static ssize_t do_tee(int argc, VALUE *argv, unsigned dflags)
286 VALUE fd_in, fd_out, len, flags;
287 struct tee_args a;
288 ssize_t bytes;
289 ssize_t total = 0;
290 unsigned waitall;
292 rb_scan_args(argc, argv, "31", &fd_in, &fd_out, &len, &flags);
293 a.len = (size_t)NUM2SIZET(len);
294 a.flags = NIL_P(flags) ? dflags : NUM2UINT(flags) | dflags;
295 waitall = a.flags & WAITALL;
296 if (waitall)
297 a.flags ^= WAITALL;
299 for (;;) {
300 a.fd_in = check_fileno(fd_in);
301 a.fd_out = check_fileno(fd_out);
302 bytes = (ssize_t)io_run(nogvl_tee, &a);
303 if (bytes == -1) {
304 if (errno == EINTR)
305 continue;
306 if (waitall && errno == EAGAIN) {
307 rb_io_wait_readable(check_fileno(fd_in));
308 errno = EAGAIN;
309 rb_io_wait_writable(check_fileno(fd_out));
310 continue;
312 if (total > 0)
313 return total;
314 return bytes;
315 } else if (bytes == 0) {
316 break;
317 } else if (waitall) {
318 total += bytes;
319 if ((a.len -= bytes) == 0)
320 return total;
321 } else {
322 return bytes;
326 return total;
330 * call-seq:
331 * IO.tee(fd_in, fd_out, len) => integer
332 * IO.tee(fd_in, fd_out, len, flags) => integer
334 * Copies up to +len+ bytes of data from +fd_in+ to +fd_out+. +fd_in+
335 * and +fd_out+ must both refer to pipe descriptors. +fd_in+ and +fd_out+
336 * may not be endpoints of the same pipe.
338 * +flags+ may be zero (the default) or IO::Splice::F_NONBLOCK
339 * Other IO::Splice flags are currently unimplemented or have no effect.
341 * Returns the number of bytes duplicated if successful.
342 * Raises EOFError when +fd_in+ is closed and emptied.
343 * Raises Errno::EAGAIN when +fd_in+ is empty and/or +fd_out+ is full
344 * and +flags+ contains IO::Splice::F_NONBLOCK
346 * Consider using IO.trytee if you are using IO::Splice::F_NONBLOCK
347 * as it avoids the cost of raising common Errno::EAGAIN exceptions.
349 * See manpage for full documentation:
350 * http://kernel.org/doc/man-pages/online/pages/man2/tee.2.html
352 static VALUE my_tee(int argc, VALUE *argv, VALUE self)
354 ssize_t n = do_tee(argc, argv, 0);
356 if (n == 0)
357 rb_eof_error();
358 if (n == -1)
359 rb_sys_fail("tee");
361 return SSIZET2NUM(n);
365 * call-seq:
366 * IO.trytee(fd_in, fd_out, len) => integer
367 * IO.trytee(fd_in, fd_out, len, flags) => integer
369 * Exactly like IO.tee, except +:EAGAIN+ is returned when either
370 * the read or write end would block instead of raising Errno::EAGAIN.
372 * IO::Splice::F_NONBLOCK is always passed for the pipe descriptor,
373 * but this can still block if the non-pipe descriptor is blocking.
375 * See IO.tee documentation for more details.
377 static VALUE trytee(int argc, VALUE *argv, VALUE self)
379 ssize_t n = do_tee(argc, argv, SPLICE_F_NONBLOCK);
381 if (n == 0)
382 return Qnil;
383 if (n == -1) {
384 if (errno == EAGAIN)
385 return sym_EAGAIN;
386 rb_sys_fail("tee");
389 return SSIZET2NUM(n);
392 struct vmsplice_args {
393 int fd;
394 struct iovec *iov;
395 unsigned long nr_segs;
396 unsigned flags;
399 static VALUE nogvl_vmsplice(void *ptr)
401 struct vmsplice_args *a = ptr;
403 return (VALUE)vmsplice(a->fd, a->iov, a->nr_segs, a->flags);
406 /* this can't be a function since we use alloca() */
407 #define ARY2IOVEC(iov,iovcnt,expect,ary) \
408 do { \
409 VALUE *cur; \
410 struct iovec *tmp; \
411 long n; \
412 cur = RARRAY_PTR(ary); \
413 n = RARRAY_LEN(ary); \
414 if (n > IOV_MAX) \
415 rb_raise(rb_eArgError, "array is larger than IOV_MAX"); \
416 iov = tmp = alloca(sizeof(struct iovec) * n); \
417 expect = 0; \
418 iovcnt = n; \
419 for (; --n >= 0; tmp++, cur++) { \
420 Check_Type(*cur, T_STRING); \
421 tmp->iov_base = RSTRING_PTR(*cur); \
422 tmp->iov_len = RSTRING_LEN(*cur); \
423 expect += tmp->iov_len; \
425 } while (0)
427 static void advance_vmsplice_args(struct vmsplice_args *a, long n)
429 struct iovec *new_iov = a->iov;
430 unsigned long i;
432 /* skip over iovecs we've already written completely */
433 for (i = 0; i < a->nr_segs; i++, new_iov++) {
434 if (n == 0)
435 break;
437 * partially written iov,
438 * modify and retry with current iovec in
439 * front
441 if (new_iov->iov_len > (size_t)n) {
442 VALUE base = (VALUE)new_iov->iov_base;
444 new_iov->iov_len -= n;
445 new_iov->iov_base = (void *)(base + n);
446 break;
449 n -= new_iov->iov_len;
452 /* setup to retry without the already-written iovecs */
453 a->nr_segs -= i;
454 a->iov = new_iov;
458 * call-seq:
459 * IO.vmsplice(fd, string_array) => integer
460 * IO.vmsplice(fd, string_array, flags) => integer
461 * IO.vmsplice(fd, string) => integer
462 * IO.vmsplice(fd, string, flags) => integer
464 * Transfers an array of strings into the pipe descriptor given by fd.
465 * +fd+ must be the writable end of a pipe.
467 * This may allow the kernel to avoid data copies in some cases.
468 * but is (probably) of limited usefulness in Ruby. If you have
469 * use cases or ideas for making this more useful for Ruby users,
470 * please tell us at ruby.io.splice@librelist.com!
472 * Also consider the "sendfile" RubyGem or IO.copy_stream in Ruby 1.9
473 * if you want to do zero-copy file transfers to pipes or sockets. As
474 * of Linux 2.6.33, sendfile(2) can copy to any output descriptor,
475 * not just sockets.
477 * See manpage for full documentation:
478 * http://kernel.org/doc/man-pages/online/pages/man2/vmsplice.2.html
480 static VALUE my_vmsplice(int argc, VALUE * argv, VALUE self)
482 ssize_t rv = 0;
483 ssize_t left;
484 struct vmsplice_args a;
485 VALUE fd, data, flags;
487 rb_scan_args(argc, argv, "21", &fd, &data, &flags);
489 switch (TYPE(data)) {
490 case T_STRING: {
491 struct iovec iov;
493 iov.iov_base = RSTRING_PTR(data);
494 iov.iov_len = (size_t)(left = (ssize_t)RSTRING_LEN(data));
495 a.iov = &iov;
496 a.nr_segs = 1;
498 break;
499 case T_ARRAY:
500 ARY2IOVEC(a.iov, a.nr_segs, left, data);
501 break;
502 default:
503 rb_raise(rb_eTypeError, "wrong argument type %s "
504 "(expected a String or Array of strings)",
505 rb_obj_classname(data));
507 a.fd = my_fileno(fd);
508 a.flags = NIL_P(flags) ? 0 : NUM2UINT(flags);
510 for (;;) {
511 ssize_t n = (ssize_t)io_run(nogvl_vmsplice, &a);
513 if (n == -1) {
514 if (errno == EAGAIN) {
515 if (a.flags & SPLICE_F_NONBLOCK) {
516 rb_sys_fail("vmsplice");
517 } else {
518 a.fd = check_fileno(fd);
519 if (rb_io_wait_writable(a.fd))
520 continue;
522 /* fall through on error */
525 * unlikely to hit this case, return the
526 * already written bytes, we'll let the next
527 * write (or close) fail instead
529 if (rv > 0)
530 break;
531 if (errno == EINTR) {
532 a.fd = check_fileno(fd);
533 continue;
535 rb_sys_fail("vmsplice");
538 rv += n;
539 left -= n;
540 if (left == 0)
541 break;
542 advance_vmsplice_args(&a, n);
545 return SSIZET2NUM(rv);
549 * call-seq:
550 * reader, writer = IO.pipe
551 * reader.pipe_size => integer
553 * Returns the pipe capacity of the underlying pipe in bytes. The
554 * default capacity is 65536 bytes since Linux 2.6.11, and 4096 bytes
555 * in previous kernels.
557 * Since the pipe is a circular buffer in the same kernel, the size
558 * of the reader is exactly the same as the size of the writer.
560 * This method is only exposed on Linux 2.6.35 or later.
562 static VALUE pipe_size(VALUE self)
564 int size = fcntl(my_fileno(self), F_GETPIPE_SZ);
566 if (size < 0)
567 rb_sys_fail("fcntl(F_GETPIPE_SZ)");
569 return INT2NUM(size);
573 * call-seq:
574 * reader, writer = IO.pipe
575 * reader.pipe_size = integer
577 * Sets and returns the pipe capacity of the underlying pipe in bytes.
579 * This MUST be a power-of-two, or Errno::EINVAL will be raised.
580 * Linux will silently increase this to be equal to the page size
581 * (4096 bytes on most architectures) if the specified value is
582 * less than the size of a page.
584 * For users without CAP_SYS_RESOURCE, this raises Errno::EPERM when
585 * attempting to specify a value greater than the value in
586 * /proc/sys/fs/pipe-max-size.
588 * Since the pipe is a circular buffer in the same kernel, the size
589 * of the reader is exactly the same as the size of the writer.
591 * Raises Errno::EBUSY if the assigned value is less than
592 * the currently filled portion of the pipe.
594 * This method is only exposed on Linux 2.6.35 or later.
596 static VALUE set_pipe_size(VALUE self, VALUE size)
598 int fd = my_fileno(self);
599 int bytes = NUM2INT(size);
600 int rv = fcntl(fd, F_SETPIPE_SZ, bytes);
602 if (rv < 0) {
603 if (errno == ENOMEM) {
604 rb_gc();
605 rv = fcntl(fd, F_SETPIPE_SZ, bytes);
607 if (rv < 0)
608 rb_sys_fail("fcntl(F_SETPIPE_SZ)");
611 return size;
614 void Init_io_splice_ext(void)
616 VALUE mSplice = rb_define_module_under(rb_cIO, "Splice");
617 struct utsname utsname;
619 rb_define_singleton_method(rb_cIO, "splice", my_splice, -1);
620 rb_define_singleton_method(rb_cIO, "trysplice", trysplice, -1);
621 rb_define_singleton_method(rb_cIO, "tee", my_tee, -1);
622 rb_define_singleton_method(rb_cIO, "trytee", trytee, -1);
623 rb_define_singleton_method(rb_cIO, "vmsplice", my_vmsplice, -1);
626 * Attempt to move pages instead of copying. This is only a hint
627 * and support for it was removed in Linux 2.6.21. It will be
628 * re-added for FUSE filesystems only in Linux 2.6.35.
630 rb_define_const(mSplice, "F_MOVE", UINT2NUM(SPLICE_F_MOVE));
631 assert(WAITALL != SPLICE_F_MOVE && "WAITALL == F_MOVE");
634 * Do not block on pipe I/O. This flag only affects the pipe(s)
635 * being spliced from/to and has no effect on the non-pipe
636 * descriptor (which requires non-blocking operation to be set
637 * explicitly).
639 * The non-blocking flag (O_NONBLOCK) on the pipe descriptors
640 * themselves are ignored by this family of functions, and
641 * using this flag is the only way to get non-blocking operation
642 * out of them.
644 rb_define_const(mSplice, "F_NONBLOCK", UINT2NUM(SPLICE_F_NONBLOCK));
645 assert(WAITALL != SPLICE_F_NONBLOCK && "WAITALL == F_NONBLOCK");
648 * Indicate that there may be more data coming into the outbound
649 * descriptor. This can allow the kernel to avoid sending partial
650 * frames from sockets. Currently only used with splice.
652 rb_define_const(mSplice, "F_MORE", UINT2NUM(SPLICE_F_MORE));
653 assert(WAITALL != SPLICE_F_MORE && "WAITALL == F_MORE");
656 * Only usable by vmsplice. This flag probably not useful in the
657 * context of Ruby applications which cannot control alignment.
659 rb_define_const(mSplice, "F_GIFT", UINT2NUM(SPLICE_F_GIFT));
660 assert(WAITALL != SPLICE_F_GIFT && "WAITALL == F_GIFT");
663 * Retry until the requested transfer is complete, this will
664 * cause IO.splice/IO.tee to never return less than the requested
665 * transfer size unless an error occored.
667 * IO.vmsplice always defaults to this behavior.
669 rb_define_const(mSplice, "WAITALL", UINT2NUM(WAITALL));
672 * The maximum size of an atomic write to a pipe
673 * POSIX requires this to be at least 512 bytes.
674 * Under Linux, this is 4096 bytes.
676 rb_define_const(mSplice, "PIPE_BUF", UINT2NUM(PIPE_BUF));
678 if (uname(&utsname) == -1)
679 rb_sys_fail("uname");
681 /* includes 2.6.35-rc[1-6] */
682 if (strcmp(utsname.release, "2.6.35") >= 0) {
683 rb_define_method(rb_cIO, "pipe_size", pipe_size, 0);
684 rb_define_method(rb_cIO, "pipe_size=", set_pipe_size, 1);
687 * fcntl() command constant used to return the size of a pipe.
688 * This constant is only defined when running Linux 2.6.35
689 * or later. For convenience, use IO#pipe_size instead.
691 rb_define_const(mSplice, "F_GETPIPE_SZ",
692 UINT2NUM(F_GETPIPE_SZ));
695 * fcntl() command constant used to set the size of a pipe.
696 * This constant is only defined when running Linux 2.6.35
697 * or later. For convenience, use IO#pipe_size= instead.
699 rb_define_const(mSplice, "F_SETPIPE_SZ",
700 UINT2NUM(F_SETPIPE_SZ));
703 sym_EAGAIN = ID2SYM(rb_intern("EAGAIN"));