kgio 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,4 @@
1
- #ifdef HAVE_ACCEPT4
2
- # define A4_SOCK_CLOEXEC SOCK_CLOEXEC
3
- # define A4_SOCK_NONBLOCK SOCK_NONBLOCK
4
- #else
1
+ #ifndef HAVE_ACCEPT4
5
2
  # ifndef _GNU_SOURCE
6
3
  # define _GNU_SOURCE
7
4
  # endif
@@ -9,15 +6,12 @@
9
6
  # include <sys/socket.h>
10
7
  # ifndef SOCK_CLOEXEC
11
8
  # if (FD_CLOEXEC == O_NONBLOCK)
12
- # define A4_SOCK_CLOEXEC 1
13
- # define A4_SOCK_NONBLOCK 2
9
+ # define SOCK_CLOEXEC 1
10
+ # define SOCK_NONBLOCK 2
14
11
  # else
15
- # define A4_SOCK_CLOEXEC FD_CLOEXEC
16
- # define A4_SOCK_NONBLOCK O_NONBLOCK
12
+ # define SOCK_CLOEXEC FD_CLOEXEC
13
+ # define SOCK_NONBLOCK O_NONBLOCK
17
14
  # endif
18
- # else
19
- # define A4_SOCK_CLOEXEC SOCK_CLOEXEC
20
- # define A4_SOCK_NONBLOCK SOCK_NONBLOCK
21
15
  # endif
22
16
 
23
17
  /* accept4() is currently a Linux-only goodie */
@@ -27,7 +21,7 @@ accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
27
21
  int fd = accept(sockfd, addr, addrlen);
28
22
 
29
23
  if (fd >= 0) {
30
- if ((flags & A4_SOCK_CLOEXEC) == A4_SOCK_CLOEXEC)
24
+ if ((flags & SOCK_CLOEXEC) == SOCK_CLOEXEC)
31
25
  (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
32
26
 
33
27
  /*
@@ -36,7 +30,7 @@ accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
36
30
  * Linux, so fcntl() is completely unnecessary
37
31
  * in most cases...
38
32
  */
39
- if ((flags & A4_SOCK_NONBLOCK) == A4_SOCK_NONBLOCK) {
33
+ if ((flags & SOCK_NONBLOCK) == SOCK_NONBLOCK) {
40
34
  int fl = fcntl(fd, F_GETFL);
41
35
 
42
36
  if ((fl & O_NONBLOCK) == 0)
@@ -0,0 +1,387 @@
1
+ #include "kgio.h"
2
+ static VALUE mKgio_WaitReadable, mKgio_WaitWritable;
3
+ static VALUE eErrno_EPIPE, eErrno_ECONNRESET;
4
+
5
+ /*
6
+ * we know MSG_DONTWAIT works properly on all stream sockets under Linux
7
+ * we can define this macro for other platforms as people care and
8
+ * notice.
9
+ */
10
+ #if defined(__linux__) && ! defined(USE_MSG_DONTWAIT)
11
+ # define USE_MSG_DONTWAIT
12
+ #endif
13
+
14
+ NORETURN(static void raise_empty_bt(VALUE, const char *));
15
+ NORETURN(static void my_eof_error(void));
16
+ NORETURN(static void wr_sys_fail(const char *));
17
+
18
+ static void raise_empty_bt(VALUE err, const char *msg)
19
+ {
20
+ VALUE exc = rb_exc_new2(err, msg);
21
+ VALUE bt = rb_ary_new();
22
+
23
+ rb_funcall(exc, rb_intern("set_backtrace"), 1, bt);
24
+ rb_exc_raise(exc);
25
+ }
26
+
27
+ static void my_eof_error(void)
28
+ {
29
+ raise_empty_bt(rb_eEOFError, "");
30
+ }
31
+
32
+ static void wr_sys_fail(const char *msg)
33
+ {
34
+ switch (errno) {
35
+ case EPIPE:
36
+ errno = 0;
37
+ raise_empty_bt(eErrno_EPIPE, msg);
38
+ case ECONNRESET:
39
+ errno = 0;
40
+ raise_empty_bt(eErrno_ECONNRESET, msg);
41
+ }
42
+ rb_sys_fail(msg);
43
+ }
44
+
45
+ static void prepare_read(struct io_args *a, int argc, VALUE *argv, VALUE io)
46
+ {
47
+ VALUE length;
48
+
49
+ a->io = io;
50
+ a->fd = my_fileno(io);
51
+ rb_scan_args(argc, argv, "11", &length, &a->buf);
52
+ a->len = NUM2LONG(length);
53
+ if (NIL_P(a->buf)) {
54
+ a->buf = rb_str_new(NULL, a->len);
55
+ } else {
56
+ StringValue(a->buf);
57
+ rb_str_resize(a->buf, a->len);
58
+ }
59
+ a->ptr = RSTRING_PTR(a->buf);
60
+ }
61
+
62
+ static int read_check(struct io_args *a, long n, const char *msg, int io_wait)
63
+ {
64
+ if (n == -1) {
65
+ if (errno == EINTR)
66
+ return -1;
67
+ rb_str_set_len(a->buf, 0);
68
+ if (errno == EAGAIN) {
69
+ if (io_wait) {
70
+ kgio_wait_readable(a->io, a->fd);
71
+
72
+ /* buf may be modified in other thread/fiber */
73
+ rb_str_resize(a->buf, a->len);
74
+ a->ptr = RSTRING_PTR(a->buf);
75
+ return -1;
76
+ } else {
77
+ a->buf = mKgio_WaitReadable;
78
+ return 0;
79
+ }
80
+ }
81
+ rb_sys_fail(msg);
82
+ }
83
+ rb_str_set_len(a->buf, n);
84
+ if (n == 0)
85
+ a->buf = Qnil;
86
+ return 0;
87
+ }
88
+
89
+ static VALUE my_read(int io_wait, int argc, VALUE *argv, VALUE io)
90
+ {
91
+ struct io_args a;
92
+ long n;
93
+
94
+ prepare_read(&a, argc, argv, io);
95
+ set_nonblocking(a.fd);
96
+ retry:
97
+ n = (long)read(a.fd, a.ptr, a.len);
98
+ if (read_check(&a, n, "read", io_wait) != 0)
99
+ goto retry;
100
+ return a.buf;
101
+ }
102
+
103
+ /*
104
+ * call-seq:
105
+ *
106
+ * io.kgio_read(maxlen) -> buffer
107
+ * io.kgio_read(maxlen, buffer) -> buffer
108
+ *
109
+ * Reads at most maxlen bytes from the stream socket. Returns with a
110
+ * newly allocated buffer, or may reuse an existing buffer if supplied.
111
+ *
112
+ * Calls the method assigned to Kgio.wait_readable, or blocks in a
113
+ * thread-safe manner for writability.
114
+ *
115
+ * Returns nil on EOF.
116
+ *
117
+ * This behaves like read(2) and IO#readpartial, NOT fread(3) or
118
+ * IO#read which possess read-in-full behavior.
119
+ */
120
+ static VALUE kgio_read(int argc, VALUE *argv, VALUE io)
121
+ {
122
+ return my_read(1, argc, argv, io);
123
+ }
124
+
125
+ /*
126
+ * Same as Kgio::PipeMethods#kgio_read, except EOFError is raised
127
+ * on EOF without a backtrace
128
+ */
129
+ static VALUE kgio_read_bang(int argc, VALUE *argv, VALUE io)
130
+ {
131
+ VALUE rv = my_read(1, argc, argv, io);
132
+
133
+ if (NIL_P(rv)) my_eof_error();
134
+ return rv;
135
+ }
136
+
137
+ /*
138
+ * call-seq:
139
+ *
140
+ * io.kgio_tryread(maxlen) -> buffer
141
+ * io.kgio_tryread(maxlen, buffer) -> buffer
142
+ *
143
+ * Reads at most maxlen bytes from the stream socket. Returns with a
144
+ * newly allocated buffer, or may reuse an existing buffer if supplied.
145
+ *
146
+ * Returns nil on EOF.
147
+ *
148
+ * Returns Kgio::WaitReadable if EAGAIN is encountered.
149
+ */
150
+ static VALUE kgio_tryread(int argc, VALUE *argv, VALUE io)
151
+ {
152
+ return my_read(0, argc, argv, io);
153
+ }
154
+
155
+ #ifdef USE_MSG_DONTWAIT
156
+ static VALUE my_recv(int io_wait, int argc, VALUE *argv, VALUE io)
157
+ {
158
+ struct io_args a;
159
+ long n;
160
+
161
+ prepare_read(&a, argc, argv, io);
162
+ retry:
163
+ n = (long)recv(a.fd, a.ptr, a.len, MSG_DONTWAIT);
164
+ if (read_check(&a, n, "recv", io_wait) != 0)
165
+ goto retry;
166
+ return a.buf;
167
+ }
168
+
169
+ /*
170
+ * This method may be optimized on some systems (e.g. GNU/Linux) to use
171
+ * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
172
+ * Otherwise this is the same as Kgio::PipeMethods#kgio_read
173
+ */
174
+ static VALUE kgio_recv(int argc, VALUE *argv, VALUE io)
175
+ {
176
+ return my_recv(1, argc, argv, io);
177
+ }
178
+
179
+ /*
180
+ * Same as Kgio::SocketMethods#kgio_read, except EOFError is raised
181
+ * on EOF without a backtrace
182
+ */
183
+ static VALUE kgio_recv_bang(int argc, VALUE *argv, VALUE io)
184
+ {
185
+ VALUE rv = my_recv(1, argc, argv, io);
186
+
187
+ if (NIL_P(rv)) my_eof_error();
188
+ return rv;
189
+ }
190
+
191
+ /*
192
+ * This method may be optimized on some systems (e.g. GNU/Linux) to use
193
+ * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
194
+ * Otherwise this is the same as Kgio::PipeMethods#kgio_tryread
195
+ */
196
+ static VALUE kgio_tryrecv(int argc, VALUE *argv, VALUE io)
197
+ {
198
+ return my_recv(0, argc, argv, io);
199
+ }
200
+ #else /* ! USE_MSG_DONTWAIT */
201
+ # define kgio_recv kgio_read
202
+ # define kgio_recv_bang kgio_read_bang
203
+ # define kgio_tryrecv kgio_tryread
204
+ #endif /* USE_MSG_DONTWAIT */
205
+
206
+ static void prepare_write(struct io_args *a, VALUE io, VALUE str)
207
+ {
208
+ a->buf = (TYPE(str) == T_STRING) ? str : rb_obj_as_string(str);
209
+ a->ptr = RSTRING_PTR(a->buf);
210
+ a->len = RSTRING_LEN(a->buf);
211
+ a->io = io;
212
+ a->fd = my_fileno(io);
213
+ }
214
+
215
+ static int write_check(struct io_args *a, long n, const char *msg, int io_wait)
216
+ {
217
+ if (a->len == n) {
218
+ done:
219
+ a->buf = Qnil;
220
+ } else if (n == -1) {
221
+ if (errno == EINTR)
222
+ return -1;
223
+ if (errno == EAGAIN) {
224
+ long written = RSTRING_LEN(a->buf) - a->len;
225
+
226
+ if (io_wait) {
227
+ kgio_wait_writable(a->io, a->fd);
228
+
229
+ /* buf may be modified in other thread/fiber */
230
+ a->len = RSTRING_LEN(a->buf) - written;
231
+ if (a->len <= 0)
232
+ goto done;
233
+ a->ptr = RSTRING_PTR(a->buf) + written;
234
+ return -1;
235
+ } else if (written > 0) {
236
+ a->buf = rb_str_new(a->ptr + n, a->len - n);
237
+ } else {
238
+ a->buf = mKgio_WaitWritable;
239
+ }
240
+ return 0;
241
+ }
242
+ wr_sys_fail(msg);
243
+ } else {
244
+ assert(n >= 0 && n < a->len && "write/send syscall broken?");
245
+ a->ptr += n;
246
+ a->len -= n;
247
+ return -1;
248
+ }
249
+ return 0;
250
+ }
251
+
252
+ static VALUE my_write(VALUE io, VALUE str, int io_wait)
253
+ {
254
+ struct io_args a;
255
+ long n;
256
+
257
+ prepare_write(&a, io, str);
258
+ set_nonblocking(a.fd);
259
+ retry:
260
+ n = (long)write(a.fd, a.ptr, a.len);
261
+ if (write_check(&a, n, "write", io_wait) != 0)
262
+ goto retry;
263
+ return a.buf;
264
+ }
265
+
266
+ /*
267
+ * call-seq:
268
+ *
269
+ * io.kgio_write(str) -> nil
270
+ *
271
+ * Returns nil when the write completes.
272
+ *
273
+ * Calls the method Kgio.wait_writable if it is set. Otherwise this
274
+ * blocks in a thread-safe manner until all data is written or a
275
+ * fatal error occurs.
276
+ */
277
+ static VALUE kgio_write(VALUE io, VALUE str)
278
+ {
279
+ return my_write(io, str, 1);
280
+ }
281
+
282
+ /*
283
+ * call-seq:
284
+ *
285
+ * io.kgio_trywrite(str) -> nil or Kgio::WaitWritable
286
+ *
287
+ * Returns nil if the write was completed in full.
288
+ *
289
+ * Returns a String containing the unwritten portion if EAGAIN
290
+ * was encountered, but some portion was successfully written.
291
+ *
292
+ * Returns Kgio::WaitWritable if EAGAIN is encountered and nothing
293
+ * was written.
294
+ */
295
+ static VALUE kgio_trywrite(VALUE io, VALUE str)
296
+ {
297
+ return my_write(io, str, 0);
298
+ }
299
+
300
+ #ifdef USE_MSG_DONTWAIT
301
+ /*
302
+ * This method behaves like Kgio::PipeMethods#kgio_write, except
303
+ * it will use send(2) with the MSG_DONTWAIT flag on sockets to
304
+ * avoid unnecessary calls to fcntl(2).
305
+ */
306
+ static VALUE my_send(VALUE io, VALUE str, int io_wait)
307
+ {
308
+ struct io_args a;
309
+ long n;
310
+
311
+ prepare_write(&a, io, str);
312
+ retry:
313
+ n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
314
+ if (write_check(&a, n, "send", io_wait) != 0)
315
+ goto retry;
316
+ return a.buf;
317
+ }
318
+
319
+ /*
320
+ * This method may be optimized on some systems (e.g. GNU/Linux) to use
321
+ * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
322
+ * Otherwise this is the same as Kgio::PipeMethods#kgio_write
323
+ */
324
+ static VALUE kgio_send(VALUE io, VALUE str)
325
+ {
326
+ return my_send(io, str, 1);
327
+ }
328
+
329
+ /*
330
+ * This method may be optimized on some systems (e.g. GNU/Linux) to use
331
+ * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
332
+ * Otherwise this is the same as Kgio::PipeMethods#kgio_trywrite
333
+ */
334
+ static VALUE kgio_trysend(VALUE io, VALUE str)
335
+ {
336
+ return my_send(io, str, 0);
337
+ }
338
+ #else /* ! USE_MSG_DONTWAIT */
339
+ # define kgio_send kgio_write
340
+ # define kgio_trysend kgio_trywrite
341
+ #endif /* ! USE_MSG_DONTWAIT */
342
+
343
+ void init_kgio_read_write(VALUE mKgio)
344
+ {
345
+ VALUE mPipeMethods, mSocketMethods;
346
+
347
+ mKgio_WaitReadable = rb_const_get(mKgio, rb_intern("WaitReadable"));
348
+ mKgio_WaitWritable = rb_const_get(mKgio, rb_intern("WaitWritable"));
349
+
350
+ /*
351
+ * Document-module: Kgio::PipeMethods
352
+ *
353
+ * This module may be used used to create classes that respond to
354
+ * various Kgio methods for reading and writing. This is included
355
+ * in Kgio::Pipe by default.
356
+ */
357
+ mPipeMethods = rb_define_module_under(mKgio, "PipeMethods");
358
+ rb_define_method(mPipeMethods, "kgio_read", kgio_read, -1);
359
+ rb_define_method(mPipeMethods, "kgio_read!", kgio_read_bang, -1);
360
+ rb_define_method(mPipeMethods, "kgio_write", kgio_write, 1);
361
+ rb_define_method(mPipeMethods, "kgio_tryread", kgio_tryread, -1);
362
+ rb_define_method(mPipeMethods, "kgio_trywrite", kgio_trywrite, 1);
363
+
364
+ /*
365
+ * Document-module: Kgio::SocketMethods
366
+ *
367
+ * This method behaves like Kgio::PipeMethods, but contains
368
+ * optimizations for sockets on certain operating systems
369
+ * (e.g. GNU/Linux).
370
+ */
371
+ mSocketMethods = rb_define_module_under(mKgio, "SocketMethods");
372
+ rb_define_method(mSocketMethods, "kgio_read", kgio_recv, -1);
373
+ rb_define_method(mSocketMethods, "kgio_read!", kgio_recv_bang, -1);
374
+ rb_define_method(mSocketMethods, "kgio_write", kgio_send, 1);
375
+ rb_define_method(mSocketMethods, "kgio_tryread", kgio_tryrecv, -1);
376
+ rb_define_method(mSocketMethods, "kgio_trywrite", kgio_trysend, 1);
377
+
378
+ /*
379
+ * Returns the client IPv4 address of the socket in dotted quad
380
+ * form as a string. This is always the value of the
381
+ * Kgio::LOCALHOST constant for UNIX domain sockets.
382
+ */
383
+ rb_define_attr(mSocketMethods, "kgio_addr", 1, 1);
384
+
385
+ eErrno_EPIPE = rb_const_get(rb_mErrno, rb_intern("EPIPE"));
386
+ eErrno_ECONNRESET = rb_const_get(rb_mErrno, rb_intern("ECONNRESET"));
387
+ }
@@ -1,3 +1,5 @@
1
+ #ifndef SOCK_FOR_FD_H
2
+ #define SOCK_FOR_FD_H
1
3
  #include <ruby.h>
2
4
  #ifdef HAVE_RUBY_IO_H
3
5
  # include <ruby/io.h>
@@ -64,3 +66,4 @@ static void init_sock_for_fd(void)
64
66
  #if SOCK_FOR_FD > 0
65
67
  # define init_sock_for_fd() if (0)
66
68
  #endif
69
+ #endif /* SOCK_FOR_FD_H */
@@ -0,0 +1,115 @@
1
+ #include "kgio.h"
2
+
3
+ static ID io_wait_rd, io_wait_wr;
4
+
5
+ void kgio_wait_readable(VALUE io, int fd)
6
+ {
7
+ if (io_wait_rd) {
8
+ (void)rb_funcall(io, io_wait_rd, 0, 0);
9
+ } else {
10
+ if (!rb_io_wait_readable(fd))
11
+ rb_sys_fail("wait readable");
12
+ }
13
+ }
14
+
15
+ void kgio_wait_writable(VALUE io, int fd)
16
+ {
17
+ if (io_wait_wr) {
18
+ (void)rb_funcall(io, io_wait_wr, 0, 0);
19
+ } else {
20
+ if (!rb_io_wait_writable(fd))
21
+ rb_sys_fail("wait writable");
22
+ }
23
+ }
24
+
25
+ /*
26
+ * call-seq:
27
+ *
28
+ * Kgio.wait_readable = :method_name
29
+ * Kgio.wait_readable = nil
30
+ *
31
+ * Sets a method for kgio_read to call when a read would block.
32
+ * This is useful for non-blocking frameworks that use Fibers,
33
+ * as the method referred to this may cause the current Fiber
34
+ * to yield execution.
35
+ *
36
+ * A special value of nil will cause Ruby to wait using the
37
+ * rb_io_wait_readable() function.
38
+ */
39
+ static VALUE set_wait_rd(VALUE mod, VALUE sym)
40
+ {
41
+ switch (TYPE(sym)) {
42
+ case T_SYMBOL:
43
+ io_wait_rd = SYM2ID(sym);
44
+ return sym;
45
+ case T_NIL:
46
+ io_wait_rd = 0;
47
+ return sym;
48
+ }
49
+ rb_raise(rb_eTypeError, "must be a symbol or nil");
50
+ return sym;
51
+ }
52
+
53
+ /*
54
+ * call-seq:
55
+ *
56
+ * Kgio.wait_writable = :method_name
57
+ * Kgio.wait_writable = nil
58
+ *
59
+ * Sets a method for kgio_write to call when a read would block.
60
+ * This is useful for non-blocking frameworks that use Fibers,
61
+ * as the method referred to this may cause the current Fiber
62
+ * to yield execution.
63
+ *
64
+ * A special value of nil will cause Ruby to wait using the
65
+ * rb_io_wait_writable() function.
66
+ */
67
+ static VALUE set_wait_wr(VALUE mod, VALUE sym)
68
+ {
69
+ switch (TYPE(sym)) {
70
+ case T_SYMBOL:
71
+ io_wait_wr = SYM2ID(sym);
72
+ return sym;
73
+ case T_NIL:
74
+ io_wait_wr = 0;
75
+ return sym;
76
+ }
77
+ rb_raise(rb_eTypeError, "must be a symbol or nil");
78
+ return sym;
79
+ }
80
+
81
+ /*
82
+ * call-seq:
83
+ *
84
+ * Kgio.wait_writable -> Symbol or nil
85
+ *
86
+ * Returns the symbolic method name of the method assigned to
87
+ * call when EAGAIN is occurs on a Kgio::PipeMethods#kgio_write
88
+ * or Kgio::SocketMethods#kgio_write call
89
+ */
90
+ static VALUE wait_wr(VALUE mod)
91
+ {
92
+ return io_wait_wr ? ID2SYM(io_wait_wr) : Qnil;
93
+ }
94
+
95
+ /*
96
+ * call-seq:
97
+ *
98
+ * Kgio.wait_readable -> Symbol or nil
99
+ *
100
+ * Returns the symbolic method name of the method assigned to
101
+ * call when EAGAIN is occurs on a Kgio::PipeMethods#kgio_read
102
+ * or Kgio::SocketMethods#kgio_read call.
103
+ */
104
+ static VALUE wait_rd(VALUE mod)
105
+ {
106
+ return io_wait_rd ? ID2SYM(io_wait_rd) : Qnil;
107
+ }
108
+
109
+ void init_kgio_wait(VALUE mKgio)
110
+ {
111
+ rb_define_singleton_method(mKgio, "wait_readable=", set_wait_rd, 1);
112
+ rb_define_singleton_method(mKgio, "wait_writable=", set_wait_wr, 1);
113
+ rb_define_singleton_method(mKgio, "wait_readable", wait_rd, 0);
114
+ rb_define_singleton_method(mKgio, "wait_writable", wait_wr, 0);
115
+ }