kqueue: modernize Struct usage for Ruby 2.5.0dev
[sleepy_penguin.git] / ext / sleepy_penguin / splice.c
blobab8c1ff4263d27f5f8b42da352749f67fc290b6d
1 #include "sleepy_penguin.h"
2 #include "sp_copy.h"
3 #ifdef HAVE_SPLICE
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <assert.h>
7 #include <sys/uio.h>
8 #include <unistd.h>
10 static VALUE sym_EAGAIN;
12 #ifndef F_LINUX_SPECIFIC_BASE
13 # define F_LINUX_SPECIFIC_BASE 1024
14 #endif
16 #ifndef F_GETPIPE_SZ
17 # define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
18 # define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
19 #endif
21 static int check_fileno(VALUE io)
23 int saved_errno = errno;
24 int fd = rb_sp_fileno(io);
25 errno = saved_errno;
26 return fd;
29 static void *nogvl_splice(void *ptr)
31 struct copy_args *a = ptr;
33 return (void *)splice(a->fd_in, a->off_in, a->fd_out, a->off_out,
34 a->len, a->flags);
37 /* :nodoc: */
38 static VALUE my_splice(VALUE mod, VALUE io_in, VALUE off_in,
39 VALUE io_out, VALUE off_out,
40 VALUE len, VALUE flags)
42 off_t i = 0, o = 0;
43 struct copy_args a;
44 ssize_t bytes;
46 a.off_in = NIL_P(off_in) ? NULL : (i = NUM2OFFT(off_in), &i);
47 a.off_out = NIL_P(off_out) ? NULL : (o = NUM2OFFT(off_out), &o);
48 a.len = NUM2SIZET(len);
49 a.flags = NUM2UINT(flags);
51 for (;;) {
52 a.fd_in = check_fileno(io_in);
53 a.fd_out = check_fileno(io_out);
54 bytes = (ssize_t)IO_RUN(nogvl_splice, &a);
55 if (bytes == 0) return Qnil;
56 if (bytes < 0) {
57 switch (errno) {
58 case EINTR: continue;
59 case EAGAIN: return sym_EAGAIN;
60 default: rb_sys_fail("splice");
63 return SSIZET2NUM(bytes);
67 struct tee_args {
68 int fd_in;
69 int fd_out;
70 size_t len;
71 unsigned flags;
74 /* runs without GVL */
75 static void *nogvl_tee(void *ptr)
77 struct tee_args *a = ptr;
79 return (void *)tee(a->fd_in, a->fd_out, a->len, a->flags);
82 /* :nodoc: */
83 static VALUE my_tee(VALUE mod, VALUE io_in, VALUE io_out,
84 VALUE len, VALUE flags)
86 struct tee_args a;
87 ssize_t bytes;
89 a.len = (size_t)NUM2SIZET(len);
90 a.flags = NUM2UINT(flags);
92 for (;;) {
93 a.fd_in = check_fileno(io_in);
94 a.fd_out = check_fileno(io_out);
95 bytes = (ssize_t)IO_RUN(nogvl_tee, &a);
96 if (bytes == 0) return Qnil;
97 if (bytes < 0) {
98 switch (errno) {
99 case EINTR: continue;
100 case EAGAIN: return sym_EAGAIN;
101 default: rb_sys_fail("tee");
104 return SSIZET2NUM(bytes);
108 void sleepy_penguin_init_splice(void)
110 VALUE mod = rb_define_module("SleepyPenguin");
111 rb_define_singleton_method(mod, "__splice", my_splice, 6);
112 rb_define_singleton_method(mod, "__tee", my_tee, 4);
115 * Attempt to move pages instead of copying. This is only a hint
116 * and support for it was removed in Linux 2.6.21. It will be
117 * re-added for FUSE filesystems only in Linux 2.6.35.
119 rb_define_const(mod, "F_MOVE", UINT2NUM(SPLICE_F_MOVE));
122 * Do not block on pipe I/O. This flag only affects the pipe(s)
123 * being spliced from/to and has no effect on the non-pipe
124 * descriptor (which requires non-blocking operation to be set
125 * explicitly).
127 * The non-blocking flag (O_NONBLOCK) on the pipe descriptors
128 * themselves are ignored by this family of functions, and
129 * using this flag is the only way to get non-blocking operation
130 * out of them.
132 * It is highly recommended this flag be set
133 * (or SleepyPenguin.trysplice used)
134 * whenever splicing from a socket into a pipe unless there is
135 * another (native) thread or process doing a blocking read on that
136 * pipe. Otherwise it is possible to block a single-threaded process
137 * if the socket buffers are larger than the pipe buffers.
139 rb_define_const(mod, "F_NONBLOCK", UINT2NUM(SPLICE_F_NONBLOCK));
142 * Indicate that there may be more data coming into the outbound
143 * descriptor. This can allow the kernel to avoid sending partial
144 * frames from sockets. Currently only used with splice.
146 rb_define_const(mod, "F_MORE", UINT2NUM(SPLICE_F_MORE));
149 * fcntl() command constant used to return the size of a pipe.
150 * This constant is only defined when running Linux 2.6.35
151 * or later.
153 * require 'fcntl'
154 * r, w = IO.pipe
155 * r.fcntl(SleepyPenguin::F_GETPIPE_SZ) => Integer
157 rb_define_const(mod, "F_GETPIPE_SZ", UINT2NUM(F_GETPIPE_SZ));
160 * fcntl() command constant used to set the size of a pipe.
161 * This constant is only defined when running Linux 2.6.35
162 * or later.
164 * call-seq:
166 * require 'fcntl'
167 * r, w = IO.pipe
168 * r.fcntl(SleepyPenguin::F_SETPIPE_SZ, 131072)
170 rb_define_const(mod, "F_SETPIPE_SZ", UINT2NUM(F_SETPIPE_SZ));
172 sym_EAGAIN = ID2SYM(rb_intern("EAGAIN"));
174 #endif