doc: better explain the need for IO::Splice::F_NONBLOCK
[ruby_io_splice.git] / ext / io_splice / io_splice_ext.c
blobfdb3397f5bac8239a3d870e21acb24edd92375e7
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 <fcntl.h>
8 #include <assert.h>
9 #include <sys/uio.h>
10 #include <limits.h>
11 #include <alloca.h>
13 #ifdef HAVE_RB_THREAD_BLOCKING_REGION
14 # define RUBY_1_8_TRAP_BEG for(;0;)
15 # define RUBY_1_8_TRAP_END for(;0;)
16 #else
17 /* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
18 # include <rubysig.h>
19 # define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
20 typedef void rb_unblock_function_t(void *);
21 typedef VALUE rb_blocking_function_t(void *);
22 static VALUE
23 rb_thread_blocking_region(
24 rb_blocking_function_t *fn, void *data1,
25 rb_unblock_function_t *ubf, void *data2)
27 VALUE rv;
29 assert(RUBY_UBF_IO == ubf && "RUBY_UBF_IO required for emulation");
31 TRAP_BEG;
32 rv = fn(data1);
33 TRAP_END;
35 return rv;
37 # define RUBY_1_8_TRAP_BEG TRAP_BEG
38 # define RUBY_1_8_TRAP_END TRAP_END
39 #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
41 #ifndef RSTRING_PTR
42 # define RSTRING_PTR(s) (RSTRING(s)->ptr)
43 #endif
44 #ifndef RSTRING_LEN
45 # define RSTRING_LEN(s) (RSTRING(s)->len)
46 #endif
47 #ifndef RARRAY_PTR
48 # define RARRAY_PTR(s) (RARRAY(s)->ptr)
49 #endif
50 #ifndef RARRAY_LEN
51 # define RARRAY_LEN(s) (RARRAY(s)->len)
52 #endif
55 * Releases GVL only iff blocking I/O is used.
56 * We'll trust programmers who use non-blocking I/O explicitly to
57 * want the fastest possible performance without resorting to threads,
58 * so releasing and them immediately reacquiring the GVL would be
59 * a waste of time.
61 static VALUE nb_io_run(rb_blocking_function_t *fn, void *data, unsigned flags)
63 if (flags & SPLICE_F_NONBLOCK)
64 return fn(data);
65 return rb_thread_blocking_region(fn, data, RUBY_UBF_IO, 0);
68 struct splice_args {
69 int fd_in;
70 off_t *off_in;
71 int fd_out;
72 off_t *off_out;
73 size_t len;
74 unsigned flags;
77 static VALUE nogvl_splice(void *ptr)
79 struct splice_args *a = ptr;
80 long n;
83 * it's still possible to block because the SPLICE_F_NONBLOCK flag
84 * only affects the pipe descriptor, not the non-pipe descriptor.
85 * So use TRAP_BEG/TRAP_END (only) to make Ruby 1.8 happy. We also
86 * don't want the TRAP_BEG/TRAP_END compatibility layer in 1.9,
87 * so we use the 1.8-only versions
89 RUBY_1_8_TRAP_BEG;
90 n = splice(a->fd_in, a->off_in, a->fd_out, a->off_out,
91 a->len, a->flags);
92 RUBY_1_8_TRAP_END;
94 return (VALUE)n;
98 * call-seq:
99 * IO.splice(fd_in, off_in, fd_out, off_out, len, flags) => integer
101 * Splice +len+ bytes from/to a pipe. Either +fd_in+ or +fd_out+
102 * MUST be a pipe. +fd_in+ and +fd_out+ may BOTH be pipes as of
103 * Linux 2.6.31 or later.
105 * +off_in+ and +off_out+ if non-nil may be used to
106 * specify an offset for the non-pipe file descriptor.
108 * +flags+ may be a bitmask of the following flags:
110 * IO::Splice::F_MOVE, IO::Splice::F_NONBLOCK, IO::Splice::F_MORE
112 * Returns the number of bytes spliced.
113 * Raises EOFError when +fd_in+ has reached end of file.
114 * Raises Errno::EAGAIN if the IO::Splice::F_NONBLOCK flag is set
115 * and the pipe has no data to read from or space to write to. May
116 * also raise Errno::EAGAIN if the non-pipe descriptor has no data
117 * to read from or space to write to.
119 * rd, wr = (pipe = IO.pipe).map { |io| io.fileno }
120 * src_io, dst_io = File.open("/path/to/src"), File.open("/path/to/dst")
121 * src, dst = src_io.fileno, dst_io.fileno
123 * nr = IO.splice(src, nil, wr, nil, IO::Splice::PIPE_CAPA, 0)
124 * IO.splice(rd, nil, dst, nil, nr, 0)
126 * As splice never exposes buffers to userspace, it will not take
127 * into account userspace buffering done by Ruby or stdio. It is
128 * also not subject to encoding/decoding filters under Ruby 1.9.
130 * See manpage for full documentation:
131 * http://kernel.org/doc/man-pages/online/pages/man2/splice.2.html
133 static VALUE my_splice(VALUE self,
134 VALUE fd_in, VALUE off_in,
135 VALUE fd_out, VALUE off_out,
136 VALUE len, VALUE flags)
138 off_t i, o;
139 long n;
140 struct splice_args a = {
141 .off_in = NIL_P(off_in) ? NULL : (i = NUM2OFFT(off_in), &i),
142 .off_out = NIL_P(off_out) ? NULL : (o = NUM2OFFT(off_out), &o),
143 .fd_in = NUM2INT(fd_in),
144 .fd_out = NUM2INT(fd_out),
145 .len = (size_t)NUM2ULONG(len),
146 .flags = NUM2UINT(flags),
149 n = (long)nb_io_run(nogvl_splice, &a, a.flags);
150 if (n == 0)
151 rb_eof_error();
152 if (n < 0)
153 rb_sys_fail("splice");
154 return LONG2NUM(n);
157 struct tee_args {
158 int fd_in;
159 int fd_out;
160 size_t len;
161 unsigned flags;
164 /* runs without GVL */
165 static VALUE nogvl_tee(void *ptr)
167 struct tee_args *a = ptr;
169 return (VALUE)tee(a->fd_in, a->fd_out, a->len, a->flags);
173 * call-seq:
174 * IO.tee(fd_in, fd_out, len, flags) => integer
176 * Copies up to +len+ bytes of data from +fd_in+ to +fd_out+. +fd_in+
177 * and +fd_out+ must both refer to pipe descriptors. +fd_in+ and +fd_out+
178 * may not be endpoints of the same pipe.
180 * +flags+ may be zero or IO::Splice::F_NONBLOCK
181 * Other IO::Splice flags are currently unimplemented or have no effect.
183 * Returns the number of bytes duplicated if successful.
184 * Raises EOFError when +fd_in+ is closed and emptied.
185 * Raises Errno::EAGAIN when +fd_in+ is empty and/or +fd_out+ is full
186 * and +flags+ contains IO::Splice::F_NONBLOCK
188 * See manpage for full documentation:
189 * http://kernel.org/doc/man-pages/online/pages/man2/tee.2.html
191 static VALUE my_tee(VALUE self,
192 VALUE fd_in, VALUE fd_out,
193 VALUE len, VALUE flags)
195 long n;
196 struct tee_args a = {
197 .fd_in = NUM2INT(fd_in),
198 .fd_out = NUM2INT(fd_out),
199 .len = (size_t)NUM2ULONG(len),
200 .flags = NUM2UINT(flags),
203 n = (long)nb_io_run(nogvl_tee, &a, a.flags);
204 if (n == 0)
205 rb_eof_error();
206 if (n < 0)
207 rb_sys_fail("tee");
209 return LONG2NUM(n);
212 struct vmsplice_args {
213 int fd;
214 struct iovec *iov;
215 unsigned long nr_segs;
216 unsigned flags;
219 static VALUE nogvl_vmsplice(void *ptr)
221 struct vmsplice_args *a = ptr;
223 return (VALUE)vmsplice(a->fd, a->iov, a->nr_segs, a->flags);
226 /* this can't be a function since we use alloca() */
227 #define ARY2IOVEC(iov,iovcnt,expect,ary) \
228 do { \
229 VALUE *cur; \
230 struct iovec *tmp; \
231 long n; \
232 Check_Type(ary, T_ARRAY); \
233 cur = RARRAY_PTR(ary); \
234 n = RARRAY_LEN(ary); \
235 if (n > IOV_MAX) \
236 rb_raise(rb_eArgError, "array is larger than IOV_MAX"); \
237 iov = tmp = alloca(sizeof(struct iovec) * n); \
238 expect = 0; \
239 iovcnt = n; \
240 for (; --n >= 0; tmp++, cur++) { \
241 Check_Type(*cur, T_STRING); \
242 tmp->iov_base = RSTRING_PTR(*cur); \
243 tmp->iov_len = RSTRING_LEN(*cur); \
244 expect += tmp->iov_len; \
246 } while (0)
248 static void advance_vmsplice_args(struct vmsplice_args *a, long n)
250 struct iovec *new_iov = a->iov;
251 int i;
253 /* skip over iovecs we've already written completely */
254 for (i = 0; i < a->nr_segs; i++, new_iov++) {
255 if (n == 0)
256 break;
258 * partially written iov,
259 * modify and retry with current iovec in
260 * front
262 if (new_iov->iov_len > (size_t)n) {
263 VALUE base = (VALUE)new_iov->iov_base;
265 new_iov->iov_len -= n;
266 new_iov->iov_base = (void *)(base + n);
267 break;
270 n -= new_iov->iov_len;
273 /* setup to retry without the already-written iovecs */
274 a->nr_segs -= i;
275 a->iov = new_iov;
279 * call-seq:
280 * IO.vmsplice(fd, string_array, flags) => integer
282 * Transfers an array of strings into the pipe descriptor given by fd.
283 * +fd+ must be the writable end of a pipe.
285 * This may allow the kernel to avoid data copies in some cases.
286 * but is (probably) of limited usefulness in Ruby.
288 * See manpage for full documentation:
289 * http://kernel.org/doc/man-pages/online/pages/man2/vmsplice.2.html
291 static VALUE my_vmsplice(VALUE self, VALUE fd, VALUE data, VALUE flags)
293 long rv = 0;
294 ssize_t left;
295 struct vmsplice_args a;
297 ARY2IOVEC(a.iov, a.nr_segs, left, data);
298 a.fd = NUM2INT(fd);
299 a.flags = NUM2UINT(flags);
301 for (;;) {
302 long n = (long)nb_io_run(nogvl_vmsplice, &a, a.flags);
304 if (n < 0) {
305 if (errno == EAGAIN) {
306 if (a.flags & SPLICE_F_NONBLOCK)
307 rb_sys_fail("vmsplice");
308 else if (rb_io_wait_writable(a.fd))
309 continue;
310 /* fall through on error */
313 * unlikely to hit this case, return the
314 * already written bytes, we'll let the next
315 * write (or close) fail instead
317 if (rv > 0)
318 break;
319 rb_sys_fail("vmsplice");
322 rv += n;
323 left -= n;
324 if (left == 0)
325 break;
326 advance_vmsplice_args(&a, n);
329 return LONG2NUM(rv);
332 void Init_io_splice_ext(void)
334 VALUE mSplice = rb_define_module_under(rb_cIO, "Splice");
336 rb_define_singleton_method(rb_cIO, "splice", my_splice, 6);
337 rb_define_singleton_method(rb_cIO, "tee", my_tee, 4);
338 rb_define_singleton_method(rb_cIO, "vmsplice", my_vmsplice, 3);
341 * Attempt to move pages instead of copying. This is only a hint
342 * and support for it was removed in Linux 2.6.21 and has not been
343 * readded as of 2.6.30.
345 rb_define_const(mSplice, "F_MOVE", UINT2NUM(SPLICE_F_MOVE));
348 * Do not block on pipe I/O. This flag only affects the pipe(s)
349 * being spliced from/to and has no effect on the non-pipe
350 * descriptor (which requires non-blocking operation to be set
351 * explicitly).
353 * The non-blocking flag (O_NONBLOCK) on the pipe descriptors
354 * themselves are ignored by this family of functions, and
355 * using this flag is the only way to get non-blocking operation
356 * out of them.
358 rb_define_const(mSplice, "F_NONBLOCK", UINT2NUM(SPLICE_F_NONBLOCK));
361 * Indicate that there may be more data coming into the outbound
362 * descriptor. This can allow the kernel to avoid sending partial
363 * frames from sockets. Currently only used with splice.
365 rb_define_const(mSplice, "F_MORE", UINT2NUM(SPLICE_F_MORE));
368 * Only usable by vmsplice. This flag probably not useful in the
369 * context of Ruby applications which cannot control alignment.
371 rb_define_const(mSplice, "F_GIFT", UINT2NUM(SPLICE_F_GIFT));
374 * The maximum size of an atomic write to a pipe
375 * POSIX requires this to be at least 512 bytes.
376 * Under Linux, this is 4096 bytes.
378 rb_define_const(mSplice, "PIPE_BUF", UINT2NUM(PIPE_BUF));