kgio 2.8.1 → 2.9.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.
- 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
|
+
}
|