kgio 2.8.1 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.manifest +4 -1
- data/ChangeLog +152 -0
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +0 -1
- data/LATEST +18 -20
- data/NEWS +22 -0
- data/Rakefile +0 -37
- data/ext/kgio/accept.c +7 -4
- data/ext/kgio/ancient_ruby.h +0 -3
- data/ext/kgio/blocking_io_region.h +6 -3
- data/ext/kgio/connect.c +11 -9
- data/ext/kgio/extconf.rb +2 -0
- data/ext/kgio/kgio.h +34 -10
- data/ext/kgio/kgio_ext.c +55 -1
- data/ext/kgio/poll.c +2 -2
- data/ext/kgio/read.c +328 -0
- data/ext/kgio/set_file_path.h +1 -0
- data/ext/kgio/tryopen.c +20 -13
- data/ext/kgio/write.c +267 -0
- data/ext/kgio/writev.c +317 -0
- data/test/test_poll.rb +0 -25
- data/test/test_syssend.rb +43 -0
- metadata +31 -42
- data/ext/kgio/read_write.c +0 -852
data/ext/kgio/read.c
ADDED
@@ -0,0 +1,328 @@
|
|
1
|
+
/* ref: rubinius b2811f260de16d1e972462e27852470364608de5 */
|
2
|
+
#define RSTRING_MODIFIED 1
|
3
|
+
#include "kgio.h"
|
4
|
+
#include "my_fileno.h"
|
5
|
+
#include "nonblock.h"
|
6
|
+
static VALUE sym_wait_readable;
|
7
|
+
|
8
|
+
#ifdef USE_MSG_DONTWAIT
|
9
|
+
static const int peek_flags = MSG_DONTWAIT|MSG_PEEK;
|
10
|
+
|
11
|
+
/* we don't need these variants, we call kgio_autopush_recv directly */
|
12
|
+
static inline void kgio_autopush_read(VALUE io) { }
|
13
|
+
|
14
|
+
#else
|
15
|
+
static const int peek_flags = MSG_PEEK;
|
16
|
+
static inline void kgio_autopush_read(VALUE io) { kgio_autopush_recv(io); }
|
17
|
+
#endif
|
18
|
+
|
19
|
+
struct rd_args {
|
20
|
+
VALUE io;
|
21
|
+
VALUE buf;
|
22
|
+
char *ptr;
|
23
|
+
long len;
|
24
|
+
int fd;
|
25
|
+
};
|
26
|
+
|
27
|
+
NORETURN(static void my_eof_error(void));
|
28
|
+
|
29
|
+
static void my_eof_error(void)
|
30
|
+
{
|
31
|
+
kgio_raise_empty_bt(rb_eEOFError, "end of file reached");
|
32
|
+
}
|
33
|
+
|
34
|
+
static void prepare_read(struct rd_args *a, int argc, VALUE *argv, VALUE io)
|
35
|
+
{
|
36
|
+
VALUE length;
|
37
|
+
|
38
|
+
a->io = io;
|
39
|
+
a->fd = my_fileno(io);
|
40
|
+
rb_scan_args(argc, argv, "11", &length, &a->buf);
|
41
|
+
a->len = NUM2LONG(length);
|
42
|
+
if (NIL_P(a->buf)) {
|
43
|
+
a->buf = rb_str_new(NULL, a->len);
|
44
|
+
} else {
|
45
|
+
StringValue(a->buf);
|
46
|
+
rb_str_modify(a->buf);
|
47
|
+
rb_str_resize(a->buf, a->len);
|
48
|
+
}
|
49
|
+
a->ptr = RSTRING_PTR(a->buf);
|
50
|
+
}
|
51
|
+
|
52
|
+
static int read_check(struct rd_args *a, long n, const char *msg, int io_wait)
|
53
|
+
{
|
54
|
+
if (n < 0) {
|
55
|
+
if (errno == EINTR) {
|
56
|
+
a->fd = my_fileno(a->io);
|
57
|
+
return -1;
|
58
|
+
}
|
59
|
+
rb_str_set_len(a->buf, 0);
|
60
|
+
if (errno == EAGAIN) {
|
61
|
+
if (io_wait) {
|
62
|
+
(void)kgio_call_wait_readable(a->io);
|
63
|
+
|
64
|
+
/* buf may be modified in other thread/fiber */
|
65
|
+
rb_str_modify(a->buf);
|
66
|
+
rb_str_resize(a->buf, a->len);
|
67
|
+
a->ptr = RSTRING_PTR(a->buf);
|
68
|
+
return -1;
|
69
|
+
} else {
|
70
|
+
a->buf = sym_wait_readable;
|
71
|
+
return 0;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
kgio_rd_sys_fail(msg);
|
75
|
+
}
|
76
|
+
rb_str_set_len(a->buf, n);
|
77
|
+
if (n == 0)
|
78
|
+
a->buf = Qnil;
|
79
|
+
return 0;
|
80
|
+
}
|
81
|
+
|
82
|
+
static VALUE my_read(int io_wait, int argc, VALUE *argv, VALUE io)
|
83
|
+
{
|
84
|
+
struct rd_args a;
|
85
|
+
long n;
|
86
|
+
|
87
|
+
prepare_read(&a, argc, argv, io);
|
88
|
+
kgio_autopush_read(io);
|
89
|
+
|
90
|
+
if (a.len > 0) {
|
91
|
+
set_nonblocking(a.fd);
|
92
|
+
retry:
|
93
|
+
n = (long)read(a.fd, a.ptr, a.len);
|
94
|
+
if (read_check(&a, n, "read", io_wait) != 0)
|
95
|
+
goto retry;
|
96
|
+
}
|
97
|
+
return a.buf;
|
98
|
+
}
|
99
|
+
|
100
|
+
/*
|
101
|
+
* call-seq:
|
102
|
+
*
|
103
|
+
* io.kgio_read(maxlen) -> buffer
|
104
|
+
* io.kgio_read(maxlen, buffer) -> buffer
|
105
|
+
*
|
106
|
+
* Reads at most maxlen bytes from the stream socket. Returns with a
|
107
|
+
* newly allocated buffer, or may reuse an existing buffer if supplied.
|
108
|
+
*
|
109
|
+
* This may block and call any method defined to +kgio_wait_readable+
|
110
|
+
* for the class.
|
111
|
+
*
|
112
|
+
* Returns nil on EOF.
|
113
|
+
*
|
114
|
+
* This behaves like read(2) and IO#readpartial, NOT fread(3) or
|
115
|
+
* IO#read which possess read-in-full behavior.
|
116
|
+
*/
|
117
|
+
static VALUE kgio_read(int argc, VALUE *argv, VALUE io)
|
118
|
+
{
|
119
|
+
return my_read(1, argc, argv, io);
|
120
|
+
}
|
121
|
+
|
122
|
+
/*
|
123
|
+
* Same as Kgio::PipeMethods#kgio_read, except EOFError is raised
|
124
|
+
* on EOF without a backtrace. This method is intended as a
|
125
|
+
* drop-in replacement for places where IO#readpartial is used, and
|
126
|
+
* may be aliased as such.
|
127
|
+
*/
|
128
|
+
static VALUE kgio_read_bang(int argc, VALUE *argv, VALUE io)
|
129
|
+
{
|
130
|
+
VALUE rv = my_read(1, argc, argv, io);
|
131
|
+
|
132
|
+
if (NIL_P(rv)) my_eof_error();
|
133
|
+
return rv;
|
134
|
+
}
|
135
|
+
|
136
|
+
/*
|
137
|
+
* call-seq:
|
138
|
+
*
|
139
|
+
* io.kgio_tryread(maxlen) -> buffer
|
140
|
+
* io.kgio_tryread(maxlen, buffer) -> buffer
|
141
|
+
*
|
142
|
+
* Reads at most maxlen bytes from the stream socket. Returns with a
|
143
|
+
* newly allocated buffer, or may reuse an existing buffer if supplied.
|
144
|
+
*
|
145
|
+
* Returns nil on EOF.
|
146
|
+
*
|
147
|
+
* Returns :wait_readable if EAGAIN is encountered.
|
148
|
+
*/
|
149
|
+
static VALUE kgio_tryread(int argc, VALUE *argv, VALUE io)
|
150
|
+
{
|
151
|
+
return my_read(0, argc, argv, io);
|
152
|
+
}
|
153
|
+
|
154
|
+
#ifdef USE_MSG_DONTWAIT
|
155
|
+
static VALUE my_recv(int io_wait, int argc, VALUE *argv, VALUE io)
|
156
|
+
{
|
157
|
+
struct rd_args a;
|
158
|
+
long n;
|
159
|
+
|
160
|
+
prepare_read(&a, argc, argv, io);
|
161
|
+
kgio_autopush_recv(io);
|
162
|
+
|
163
|
+
if (a.len > 0) {
|
164
|
+
retry:
|
165
|
+
n = (long)recv(a.fd, a.ptr, a.len, MSG_DONTWAIT);
|
166
|
+
if (read_check(&a, n, "recv", io_wait) != 0)
|
167
|
+
goto retry;
|
168
|
+
}
|
169
|
+
return a.buf;
|
170
|
+
}
|
171
|
+
|
172
|
+
/*
|
173
|
+
* This method may be optimized on some systems (e.g. GNU/Linux) to use
|
174
|
+
* MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
|
175
|
+
* Otherwise this is the same as Kgio::PipeMethods#kgio_read
|
176
|
+
*/
|
177
|
+
static VALUE kgio_recv(int argc, VALUE *argv, VALUE io)
|
178
|
+
{
|
179
|
+
return my_recv(1, argc, argv, io);
|
180
|
+
}
|
181
|
+
|
182
|
+
/*
|
183
|
+
* Same as Kgio::SocketMethods#kgio_read, except EOFError is raised
|
184
|
+
* on EOF without a backtrace
|
185
|
+
*/
|
186
|
+
static VALUE kgio_recv_bang(int argc, VALUE *argv, VALUE io)
|
187
|
+
{
|
188
|
+
VALUE rv = my_recv(1, argc, argv, io);
|
189
|
+
|
190
|
+
if (NIL_P(rv)) my_eof_error();
|
191
|
+
return rv;
|
192
|
+
}
|
193
|
+
|
194
|
+
/*
|
195
|
+
* This method may be optimized on some systems (e.g. GNU/Linux) to use
|
196
|
+
* MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
|
197
|
+
* Otherwise this is the same as Kgio::PipeMethods#kgio_tryread
|
198
|
+
*/
|
199
|
+
static VALUE kgio_tryrecv(int argc, VALUE *argv, VALUE io)
|
200
|
+
{
|
201
|
+
return my_recv(0, argc, argv, io);
|
202
|
+
}
|
203
|
+
#else /* ! USE_MSG_DONTWAIT */
|
204
|
+
# define kgio_recv kgio_read
|
205
|
+
# define kgio_recv_bang kgio_read_bang
|
206
|
+
# define kgio_tryrecv kgio_tryread
|
207
|
+
#endif /* USE_MSG_DONTWAIT */
|
208
|
+
|
209
|
+
static VALUE my_peek(int io_wait, int argc, VALUE *argv, VALUE io)
|
210
|
+
{
|
211
|
+
struct rd_args a;
|
212
|
+
long n;
|
213
|
+
|
214
|
+
prepare_read(&a, argc, argv, io);
|
215
|
+
kgio_autopush_recv(io);
|
216
|
+
|
217
|
+
if (a.len > 0) {
|
218
|
+
if (peek_flags == MSG_PEEK)
|
219
|
+
set_nonblocking(a.fd);
|
220
|
+
retry:
|
221
|
+
n = (long)recv(a.fd, a.ptr, a.len, peek_flags);
|
222
|
+
if (read_check(&a, n, "recv(MSG_PEEK)", io_wait) != 0)
|
223
|
+
goto retry;
|
224
|
+
}
|
225
|
+
return a.buf;
|
226
|
+
}
|
227
|
+
|
228
|
+
/*
|
229
|
+
* call-seq:
|
230
|
+
*
|
231
|
+
* socket.kgio_trypeek(maxlen) -> buffer
|
232
|
+
* socket.kgio_trypeek(maxlen, buffer) -> buffer
|
233
|
+
*
|
234
|
+
* Like kgio_tryread, except it uses MSG_PEEK so it does not drain the
|
235
|
+
* socket buffer. A subsequent read of any type (including another peek)
|
236
|
+
* will return the same data.
|
237
|
+
*/
|
238
|
+
static VALUE kgio_trypeek(int argc, VALUE *argv, VALUE io)
|
239
|
+
{
|
240
|
+
return my_peek(0, argc, argv, io);
|
241
|
+
}
|
242
|
+
|
243
|
+
/*
|
244
|
+
* call-seq:
|
245
|
+
*
|
246
|
+
* socket.kgio_peek(maxlen) -> buffer
|
247
|
+
* socket.kgio_peek(maxlen, buffer) -> buffer
|
248
|
+
*
|
249
|
+
* Like kgio_read, except it uses MSG_PEEK so it does not drain the
|
250
|
+
* socket buffer. A subsequent read of any type (including another peek)
|
251
|
+
* will return the same data.
|
252
|
+
*/
|
253
|
+
static VALUE kgio_peek(int argc, VALUE *argv, VALUE io)
|
254
|
+
{
|
255
|
+
return my_peek(1, argc, argv, io);
|
256
|
+
}
|
257
|
+
|
258
|
+
/*
|
259
|
+
* call-seq:
|
260
|
+
*
|
261
|
+
* Kgio.trypeek(socket, maxlen) -> buffer
|
262
|
+
* Kgio.trypeek(socket, maxlen, buffer) -> buffer
|
263
|
+
*
|
264
|
+
* Like Kgio.tryread, except it uses MSG_PEEK so it does not drain the
|
265
|
+
* socket buffer. This can only be used on sockets and not pipe objects.
|
266
|
+
* Maybe used in place of SocketMethods#kgio_trypeek for non-Kgio objects
|
267
|
+
*/
|
268
|
+
static VALUE s_trypeek(int argc, VALUE *argv, VALUE mod)
|
269
|
+
{
|
270
|
+
if (argc <= 1)
|
271
|
+
rb_raise(rb_eArgError, "wrong number of arguments");
|
272
|
+
return my_peek(0, argc - 1, &argv[1], argv[0]);
|
273
|
+
}
|
274
|
+
|
275
|
+
/*
|
276
|
+
* call-seq:
|
277
|
+
*
|
278
|
+
* Kgio.tryread(io, maxlen) -> buffer
|
279
|
+
* Kgio.tryread(io, maxlen, buffer) -> buffer
|
280
|
+
*
|
281
|
+
* Returns nil on EOF.
|
282
|
+
* Returns :wait_readable if EAGAIN is encountered.
|
283
|
+
*
|
284
|
+
* Maybe used in place of PipeMethods#kgio_tryread for non-Kgio objects
|
285
|
+
*/
|
286
|
+
static VALUE s_tryread(int argc, VALUE *argv, VALUE mod)
|
287
|
+
{
|
288
|
+
if (argc <= 1)
|
289
|
+
rb_raise(rb_eArgError, "wrong number of arguments");
|
290
|
+
return my_read(0, argc - 1, &argv[1], argv[0]);
|
291
|
+
}
|
292
|
+
|
293
|
+
void init_kgio_read(void)
|
294
|
+
{
|
295
|
+
VALUE mPipeMethods, mSocketMethods;
|
296
|
+
VALUE mKgio = rb_define_module("Kgio");
|
297
|
+
|
298
|
+
sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
|
299
|
+
|
300
|
+
rb_define_singleton_method(mKgio, "tryread", s_tryread, -1);
|
301
|
+
rb_define_singleton_method(mKgio, "trypeek", s_trypeek, -1);
|
302
|
+
|
303
|
+
/*
|
304
|
+
* Document-module: Kgio::PipeMethods
|
305
|
+
*
|
306
|
+
* This module may be used used to create classes that respond to
|
307
|
+
* various Kgio methods for reading and writing. This is included
|
308
|
+
* in Kgio::Pipe by default.
|
309
|
+
*/
|
310
|
+
mPipeMethods = rb_define_module_under(mKgio, "PipeMethods");
|
311
|
+
rb_define_method(mPipeMethods, "kgio_read", kgio_read, -1);
|
312
|
+
rb_define_method(mPipeMethods, "kgio_read!", kgio_read_bang, -1);
|
313
|
+
rb_define_method(mPipeMethods, "kgio_tryread", kgio_tryread, -1);
|
314
|
+
|
315
|
+
/*
|
316
|
+
* Document-module: Kgio::SocketMethods
|
317
|
+
*
|
318
|
+
* This method behaves like Kgio::PipeMethods, but contains
|
319
|
+
* optimizations for sockets on certain operating systems
|
320
|
+
* (e.g. GNU/Linux).
|
321
|
+
*/
|
322
|
+
mSocketMethods = rb_define_module_under(mKgio, "SocketMethods");
|
323
|
+
rb_define_method(mSocketMethods, "kgio_read", kgio_recv, -1);
|
324
|
+
rb_define_method(mSocketMethods, "kgio_read!", kgio_recv_bang, -1);
|
325
|
+
rb_define_method(mSocketMethods, "kgio_tryread", kgio_tryrecv, -1);
|
326
|
+
rb_define_method(mSocketMethods, "kgio_trypeek", kgio_trypeek, -1);
|
327
|
+
rb_define_method(mSocketMethods, "kgio_peek", kgio_peek, -1);
|
328
|
+
}
|
data/ext/kgio/set_file_path.h
CHANGED
data/ext/kgio/tryopen.c
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
/* We do not modify RSTRING in this file, so RSTRING_MODIFIED is not needed */
|
1
2
|
#include <ruby.h>
|
2
3
|
#ifdef HAVE_RUBY_IO_H
|
3
4
|
# include <ruby/io.h>
|
@@ -17,6 +18,7 @@
|
|
17
18
|
#include <errno.h>
|
18
19
|
#include "set_file_path.h"
|
19
20
|
#include "ancient_ruby.h"
|
21
|
+
#include "kgio.h"
|
20
22
|
|
21
23
|
static ID id_for_fd, id_to_path, id_path;
|
22
24
|
static st_table *errno2sym;
|
@@ -38,7 +40,7 @@ static VALUE nogvl_open(void *ptr)
|
|
38
40
|
return (VALUE)rb_cloexec_open(o->pathname, o->flags, o->mode);
|
39
41
|
}
|
40
42
|
|
41
|
-
#ifndef
|
43
|
+
#ifndef KGIO_HAVE_THREAD_CALL_WITHOUT_GVL
|
42
44
|
# define RUBY_UBF_IO ((void *)(-1))
|
43
45
|
# include "rubysig.h"
|
44
46
|
typedef void rb_unblock_function_t(void *);
|
@@ -57,7 +59,7 @@ static VALUE my_thread_blocking_region(
|
|
57
59
|
}
|
58
60
|
#define rb_thread_blocking_region(fn,data1,ubf,data2) \
|
59
61
|
my_thread_blocking_region((fn),(data1),(ubf),(data2))
|
60
|
-
#endif /* !
|
62
|
+
#endif /* ! KGIO_HAVE_THREAD_CALL_WITHOUT_GVL */
|
61
63
|
|
62
64
|
/*
|
63
65
|
* call-seq:
|
@@ -80,7 +82,7 @@ static VALUE my_thread_blocking_region(
|
|
80
82
|
*/
|
81
83
|
static VALUE s_tryopen(int argc, VALUE *argv, VALUE klass)
|
82
84
|
{
|
83
|
-
|
85
|
+
long fd;
|
84
86
|
VALUE pathname, flags, mode;
|
85
87
|
struct open_args o;
|
86
88
|
int retried = 0;
|
@@ -105,7 +107,7 @@ static VALUE s_tryopen(int argc, VALUE *argv, VALUE klass)
|
|
105
107
|
}
|
106
108
|
|
107
109
|
retry:
|
108
|
-
fd = (
|
110
|
+
fd = (long)rb_thread_blocking_region(nogvl_open, &o, RUBY_UBF_IO, 0);
|
109
111
|
if (fd < 0) {
|
110
112
|
if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
|
111
113
|
rb_gc();
|
@@ -124,7 +126,7 @@ retry:
|
|
124
126
|
return rv;
|
125
127
|
}
|
126
128
|
}
|
127
|
-
rv = rb_funcall(klass, id_for_fd, 1,
|
129
|
+
rv = rb_funcall(klass, id_for_fd, 1, LONG2FIX(fd));
|
128
130
|
set_file_path(rv, pathname);
|
129
131
|
return rv;
|
130
132
|
}
|
@@ -135,8 +137,7 @@ void init_kgio_tryopen(void)
|
|
135
137
|
VALUE mPipeMethods = rb_const_get(mKgio, rb_intern("PipeMethods"));
|
136
138
|
VALUE cFile;
|
137
139
|
VALUE tmp;
|
138
|
-
|
139
|
-
long len;
|
140
|
+
long i, len;
|
140
141
|
|
141
142
|
id_path = rb_intern("path");
|
142
143
|
id_for_fd = rb_intern("for_fd");
|
@@ -161,16 +162,22 @@ void init_kgio_tryopen(void)
|
|
161
162
|
|
162
163
|
errno2sym = st_init_numtable();
|
163
164
|
tmp = rb_funcall(rb_mErrno, rb_intern("constants"), 0);
|
164
|
-
ptr = RARRAY_PTR(tmp);
|
165
165
|
len = RARRAY_LEN(tmp);
|
166
|
-
for (;
|
166
|
+
for (i = 0; i < len; i++) {
|
167
167
|
VALUE error;
|
168
|
+
VALUE err = rb_ary_entry(tmp, i);
|
168
169
|
ID const_id;
|
169
170
|
|
170
|
-
switch (TYPE(
|
171
|
-
case T_SYMBOL: const_id = SYM2ID(
|
172
|
-
case T_STRING: const_id = rb_intern(RSTRING_PTR(
|
173
|
-
default:
|
171
|
+
switch (TYPE(err)) {
|
172
|
+
case T_SYMBOL: const_id = SYM2ID(err); break;
|
173
|
+
case T_STRING: const_id = rb_intern(RSTRING_PTR(err)); break;
|
174
|
+
default: {
|
175
|
+
VALUE i = rb_inspect(err);
|
176
|
+
const char *s = RSTRING_PTR(i);
|
177
|
+
|
178
|
+
rb_bug("constant not a symbol or string: %s", s);
|
179
|
+
RB_GC_GUARD(i);
|
180
|
+
}
|
174
181
|
}
|
175
182
|
|
176
183
|
error = rb_const_get(rb_mErrno, const_id);
|
data/ext/kgio/write.c
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
/* we do not modify RSTRING pointers here */
|
2
|
+
#include "kgio.h"
|
3
|
+
#include "my_fileno.h"
|
4
|
+
#include "nonblock.h"
|
5
|
+
static VALUE sym_wait_writable;
|
6
|
+
|
7
|
+
/* prefer rb_str_subseq because we don't use negative offsets */
|
8
|
+
#ifndef HAVE_RB_STR_SUBSEQ
|
9
|
+
#define rb_str_subseq rb_str_substr
|
10
|
+
#endif
|
11
|
+
|
12
|
+
struct wr_args {
|
13
|
+
VALUE io;
|
14
|
+
VALUE buf;
|
15
|
+
const char *ptr;
|
16
|
+
long len;
|
17
|
+
int fd;
|
18
|
+
int flags;
|
19
|
+
};
|
20
|
+
|
21
|
+
static void prepare_write(struct wr_args *a, VALUE io, VALUE str)
|
22
|
+
{
|
23
|
+
a->buf = (TYPE(str) == T_STRING) ? str : rb_obj_as_string(str);
|
24
|
+
a->ptr = RSTRING_PTR(a->buf);
|
25
|
+
a->len = RSTRING_LEN(a->buf);
|
26
|
+
a->io = io;
|
27
|
+
a->fd = my_fileno(io);
|
28
|
+
}
|
29
|
+
|
30
|
+
static int write_check(struct wr_args *a, long n, const char *msg, int io_wait)
|
31
|
+
{
|
32
|
+
if (a->len == n) {
|
33
|
+
done:
|
34
|
+
a->buf = Qnil;
|
35
|
+
} else if (n < 0) {
|
36
|
+
if (errno == EINTR) {
|
37
|
+
a->fd = my_fileno(a->io);
|
38
|
+
return -1;
|
39
|
+
}
|
40
|
+
if (errno == EAGAIN) {
|
41
|
+
long written = RSTRING_LEN(a->buf) - a->len;
|
42
|
+
|
43
|
+
if (io_wait) {
|
44
|
+
(void)kgio_call_wait_writable(a->io);
|
45
|
+
|
46
|
+
/* buf may be modified in other thread/fiber */
|
47
|
+
a->len = RSTRING_LEN(a->buf) - written;
|
48
|
+
if (a->len <= 0)
|
49
|
+
goto done;
|
50
|
+
a->ptr = RSTRING_PTR(a->buf) + written;
|
51
|
+
return -1;
|
52
|
+
} else if (written > 0) {
|
53
|
+
a->buf = rb_str_subseq(a->buf, written, a->len);
|
54
|
+
} else {
|
55
|
+
a->buf = sym_wait_writable;
|
56
|
+
}
|
57
|
+
return 0;
|
58
|
+
}
|
59
|
+
kgio_wr_sys_fail(msg);
|
60
|
+
} else {
|
61
|
+
assert(n >= 0 && n < a->len && "write/send syscall broken?");
|
62
|
+
a->ptr += n;
|
63
|
+
a->len -= n;
|
64
|
+
return -1;
|
65
|
+
}
|
66
|
+
return 0;
|
67
|
+
}
|
68
|
+
|
69
|
+
static VALUE my_write(VALUE io, VALUE str, int io_wait)
|
70
|
+
{
|
71
|
+
struct wr_args a;
|
72
|
+
long n;
|
73
|
+
|
74
|
+
prepare_write(&a, io, str);
|
75
|
+
set_nonblocking(a.fd);
|
76
|
+
retry:
|
77
|
+
n = (long)write(a.fd, a.ptr, a.len);
|
78
|
+
if (write_check(&a, n, "write", io_wait) != 0)
|
79
|
+
goto retry;
|
80
|
+
if (TYPE(a.buf) != T_SYMBOL)
|
81
|
+
kgio_autopush_write(io);
|
82
|
+
return a.buf;
|
83
|
+
}
|
84
|
+
|
85
|
+
/*
|
86
|
+
* call-seq:
|
87
|
+
*
|
88
|
+
* io.kgio_write(str) -> nil
|
89
|
+
*
|
90
|
+
* Returns nil when the write completes.
|
91
|
+
*
|
92
|
+
* This may block and call any method defined to +kgio_wait_writable+
|
93
|
+
* for the class.
|
94
|
+
*/
|
95
|
+
static VALUE kgio_write(VALUE io, VALUE str)
|
96
|
+
{
|
97
|
+
return my_write(io, str, 1);
|
98
|
+
}
|
99
|
+
|
100
|
+
/*
|
101
|
+
* call-seq:
|
102
|
+
*
|
103
|
+
* io.kgio_trywrite(str) -> nil, String or :wait_writable
|
104
|
+
*
|
105
|
+
* Returns nil if the write was completed in full.
|
106
|
+
*
|
107
|
+
* Returns a String containing the unwritten portion if EAGAIN
|
108
|
+
* was encountered, but some portion was successfully written.
|
109
|
+
*
|
110
|
+
* Returns :wait_writable if EAGAIN is encountered and nothing
|
111
|
+
* was written.
|
112
|
+
*/
|
113
|
+
static VALUE kgio_trywrite(VALUE io, VALUE str)
|
114
|
+
{
|
115
|
+
return my_write(io, str, 0);
|
116
|
+
}
|
117
|
+
|
118
|
+
#ifdef USE_MSG_DONTWAIT
|
119
|
+
/*
|
120
|
+
* This method behaves like Kgio::PipeMethods#kgio_write, except
|
121
|
+
* it will use send(2) with the MSG_DONTWAIT flag on sockets to
|
122
|
+
* avoid unnecessary calls to fcntl(2).
|
123
|
+
*/
|
124
|
+
static VALUE my_send(VALUE io, VALUE str, int io_wait)
|
125
|
+
{
|
126
|
+
struct wr_args a;
|
127
|
+
long n;
|
128
|
+
|
129
|
+
prepare_write(&a, io, str);
|
130
|
+
retry:
|
131
|
+
n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
|
132
|
+
if (write_check(&a, n, "send", io_wait) != 0)
|
133
|
+
goto retry;
|
134
|
+
if (TYPE(a.buf) != T_SYMBOL)
|
135
|
+
kgio_autopush_send(io);
|
136
|
+
return a.buf;
|
137
|
+
}
|
138
|
+
|
139
|
+
/*
|
140
|
+
* This method may be optimized on some systems (e.g. GNU/Linux) to use
|
141
|
+
* MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
|
142
|
+
* Otherwise this is the same as Kgio::PipeMethods#kgio_write
|
143
|
+
*/
|
144
|
+
static VALUE kgio_send(VALUE io, VALUE str)
|
145
|
+
{
|
146
|
+
return my_send(io, str, 1);
|
147
|
+
}
|
148
|
+
|
149
|
+
/*
|
150
|
+
* This method may be optimized on some systems (e.g. GNU/Linux) to use
|
151
|
+
* MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
|
152
|
+
* Otherwise this is the same as Kgio::PipeMethods#kgio_trywrite
|
153
|
+
*/
|
154
|
+
static VALUE kgio_trysend(VALUE io, VALUE str)
|
155
|
+
{
|
156
|
+
return my_send(io, str, 0);
|
157
|
+
}
|
158
|
+
#else /* ! USE_MSG_DONTWAIT */
|
159
|
+
# define kgio_send kgio_write
|
160
|
+
# define kgio_trysend kgio_trywrite
|
161
|
+
#endif /* ! USE_MSG_DONTWAIT */
|
162
|
+
|
163
|
+
#if defined(KGIO_HAVE_THREAD_CALL_WITHOUT_GVL)
|
164
|
+
# include "blocking_io_region.h"
|
165
|
+
#ifdef MSG_DONTWAIT /* Linux only */
|
166
|
+
# define MY_MSG_DONTWAIT (MSG_DONTWAIT)
|
167
|
+
#else
|
168
|
+
# define MY_MSG_DONTWAIT (0)
|
169
|
+
#endif
|
170
|
+
|
171
|
+
static VALUE nogvl_send(void *ptr)
|
172
|
+
{
|
173
|
+
struct wr_args *a = ptr;
|
174
|
+
|
175
|
+
return (VALUE)send(a->fd, a->ptr, a->len, a->flags);
|
176
|
+
}
|
177
|
+
/*
|
178
|
+
* call-seq:
|
179
|
+
*
|
180
|
+
* io.kgio_syssend(str, flags) -> nil, String or :wait_writable
|
181
|
+
*
|
182
|
+
* Returns nil if the write was completed in full.
|
183
|
+
*
|
184
|
+
* Returns a String containing the unwritten portion if EAGAIN
|
185
|
+
* was encountered, but some portion was successfully written.
|
186
|
+
*
|
187
|
+
* Returns :wait_writable if EAGAIN is encountered and nothing
|
188
|
+
* was written.
|
189
|
+
*
|
190
|
+
* This method is only available on Ruby 1.9.3 or later.
|
191
|
+
*/
|
192
|
+
static VALUE kgio_syssend(VALUE io, VALUE str, VALUE flags)
|
193
|
+
{
|
194
|
+
struct wr_args a;
|
195
|
+
long n;
|
196
|
+
|
197
|
+
a.flags = NUM2INT(flags);
|
198
|
+
prepare_write(&a, io, str);
|
199
|
+
if (a.flags & MY_MSG_DONTWAIT) {
|
200
|
+
do {
|
201
|
+
n = (long)send(a.fd, a.ptr, a.len, a.flags);
|
202
|
+
} while (write_check(&a, n, "send", 0) != 0);
|
203
|
+
} else {
|
204
|
+
do {
|
205
|
+
n = (long)rb_thread_io_blocking_region(
|
206
|
+
nogvl_send, &a, a.fd);
|
207
|
+
} while (write_check(&a, n, "send", 0) != 0);
|
208
|
+
}
|
209
|
+
return a.buf;
|
210
|
+
}
|
211
|
+
#endif /* HAVE_RB_THREAD_IO_BLOCKING_REGION */
|
212
|
+
|
213
|
+
/*
|
214
|
+
* call-seq:
|
215
|
+
*
|
216
|
+
* Kgio.trywrite(io, str) -> nil, String or :wait_writable
|
217
|
+
*
|
218
|
+
* Returns nil if the write was completed in full.
|
219
|
+
*
|
220
|
+
* Returns a String containing the unwritten portion if EAGAIN
|
221
|
+
* was encountered, but some portion was successfully written.
|
222
|
+
*
|
223
|
+
* Returns :wait_writable if EAGAIN is encountered and nothing
|
224
|
+
* was written.
|
225
|
+
*
|
226
|
+
* Maybe used in place of PipeMethods#kgio_trywrite for non-Kgio objects
|
227
|
+
*/
|
228
|
+
static VALUE s_trywrite(VALUE mod, VALUE io, VALUE str)
|
229
|
+
{
|
230
|
+
return my_write(io, str, 0);
|
231
|
+
}
|
232
|
+
|
233
|
+
void init_kgio_write(void)
|
234
|
+
{
|
235
|
+
VALUE mPipeMethods, mSocketMethods;
|
236
|
+
VALUE mKgio = rb_define_module("Kgio");
|
237
|
+
|
238
|
+
sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
|
239
|
+
|
240
|
+
rb_define_singleton_method(mKgio, "trywrite", s_trywrite, 2);
|
241
|
+
|
242
|
+
/*
|
243
|
+
* Document-module: Kgio::PipeMethods
|
244
|
+
*
|
245
|
+
* This module may be used used to create classes that respond to
|
246
|
+
* various Kgio methods for reading and writing. This is included
|
247
|
+
* in Kgio::Pipe by default.
|
248
|
+
*/
|
249
|
+
mPipeMethods = rb_define_module_under(mKgio, "PipeMethods");
|
250
|
+
rb_define_method(mPipeMethods, "kgio_write", kgio_write, 1);
|
251
|
+
rb_define_method(mPipeMethods, "kgio_trywrite", kgio_trywrite, 1);
|
252
|
+
|
253
|
+
/*
|
254
|
+
* Document-module: Kgio::SocketMethods
|
255
|
+
*
|
256
|
+
* This method behaves like Kgio::PipeMethods, but contains
|
257
|
+
* optimizations for sockets on certain operating systems
|
258
|
+
* (e.g. GNU/Linux).
|
259
|
+
*/
|
260
|
+
mSocketMethods = rb_define_module_under(mKgio, "SocketMethods");
|
261
|
+
rb_define_method(mSocketMethods, "kgio_write", kgio_send, 1);
|
262
|
+
rb_define_method(mSocketMethods, "kgio_trywrite", kgio_trysend, 1);
|
263
|
+
|
264
|
+
#ifdef USE_MSG_DONTWAIT
|
265
|
+
rb_define_method(mSocketMethods, "kgio_syssend", kgio_syssend, 2);
|
266
|
+
#endif
|
267
|
+
}
|