kgio 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }