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/writev.c
ADDED
@@ -0,0 +1,317 @@
|
|
1
|
+
/*
|
2
|
+
* we're currently too lazy to use rb_ensure to free an allocation, so we
|
3
|
+
* the abuse rb_str_* API for a temporary buffer
|
4
|
+
*/
|
5
|
+
#define RSTRING_MODIFIED 1
|
6
|
+
|
7
|
+
#include "kgio.h"
|
8
|
+
#include "my_fileno.h"
|
9
|
+
#include "nonblock.h"
|
10
|
+
#ifdef HAVE_WRITEV
|
11
|
+
# include <sys/uio.h>
|
12
|
+
# define USE_WRITEV 1
|
13
|
+
#else
|
14
|
+
# define USE_WRITEV 0
|
15
|
+
static ssize_t assert_writev(int fd, void* iov, int len)
|
16
|
+
{
|
17
|
+
assert(0 && "you should not try to call writev");
|
18
|
+
return -1;
|
19
|
+
}
|
20
|
+
# define writev assert_writev
|
21
|
+
#endif
|
22
|
+
static VALUE sym_wait_writable;
|
23
|
+
|
24
|
+
#ifndef HAVE_WRITEV
|
25
|
+
#define iovec my_iovec
|
26
|
+
struct my_iovec {
|
27
|
+
void *iov_base;
|
28
|
+
size_t iov_len;
|
29
|
+
};
|
30
|
+
#endif
|
31
|
+
|
32
|
+
/* tests for choosing following constants were done on Linux 3.0 x86_64
|
33
|
+
* (Ubuntu 12.04) Core i3 i3-2330M slowed to 1600MHz
|
34
|
+
* testing script https://gist.github.com/2850641
|
35
|
+
* fill free to make more thorough testing and choose better value
|
36
|
+
*/
|
37
|
+
|
38
|
+
/* test shows that its meaningless to set WRITEV_MEMLIMIT more that 1M
|
39
|
+
* even when tcp_wmem set to relatively high value (2M) (in fact, it becomes
|
40
|
+
* even slower). 512K performs a bit better in average case. */
|
41
|
+
#define WRITEV_MEMLIMIT (512*1024)
|
42
|
+
/* same test shows that custom_writev is faster than glibc writev when
|
43
|
+
* average string is smaller than ~500 bytes and slower when average strings
|
44
|
+
* is greater then ~600 bytes. 512 bytes were choosen cause current compilers
|
45
|
+
* turns x/512 into x>>9 */
|
46
|
+
#define WRITEV_IMPL_THRESHOLD 512
|
47
|
+
|
48
|
+
static unsigned int iov_max = 1024; /* this could be overriden in init */
|
49
|
+
|
50
|
+
struct wrv_args {
|
51
|
+
VALUE io;
|
52
|
+
VALUE buf;
|
53
|
+
VALUE vec_buf; /* FIXME: this requires RSTRING_MODIFY for rbx */
|
54
|
+
struct iovec *vec;
|
55
|
+
unsigned long iov_cnt;
|
56
|
+
size_t batch_len;
|
57
|
+
int something_written;
|
58
|
+
int fd;
|
59
|
+
};
|
60
|
+
|
61
|
+
static ssize_t custom_writev(int fd, const struct iovec *vec, unsigned int iov_cnt, size_t total_len)
|
62
|
+
{
|
63
|
+
unsigned int i;
|
64
|
+
ssize_t result;
|
65
|
+
char *buf, *curbuf;
|
66
|
+
const struct iovec *curvec = vec;
|
67
|
+
|
68
|
+
/* we do not want to use ruby's xmalloc because
|
69
|
+
* it can fire GC, and we'll free buffer shortly anyway */
|
70
|
+
curbuf = buf = malloc(total_len);
|
71
|
+
if (buf == NULL) return -1;
|
72
|
+
|
73
|
+
for (i = 0; i < iov_cnt; i++, curvec++) {
|
74
|
+
memcpy(curbuf, curvec->iov_base, curvec->iov_len);
|
75
|
+
curbuf += curvec->iov_len;
|
76
|
+
}
|
77
|
+
|
78
|
+
result = write(fd, buf, total_len);
|
79
|
+
|
80
|
+
/* well, it seems that `free` could not change errno
|
81
|
+
* but lets save it anyway */
|
82
|
+
i = errno;
|
83
|
+
free(buf);
|
84
|
+
errno = i;
|
85
|
+
|
86
|
+
return result;
|
87
|
+
}
|
88
|
+
|
89
|
+
static void prepare_writev(struct wrv_args *a, VALUE io, VALUE ary)
|
90
|
+
{
|
91
|
+
a->io = io;
|
92
|
+
a->fd = my_fileno(io);
|
93
|
+
a->something_written = 0;
|
94
|
+
|
95
|
+
if (TYPE(ary) == T_ARRAY)
|
96
|
+
/* rb_ary_subseq will not copy array unless it modified */
|
97
|
+
a->buf = rb_ary_subseq(ary, 0, RARRAY_LEN(ary));
|
98
|
+
else
|
99
|
+
a->buf = rb_Array(ary);
|
100
|
+
|
101
|
+
a->vec_buf = rb_str_new(0, 0);
|
102
|
+
a->vec = NULL;
|
103
|
+
}
|
104
|
+
|
105
|
+
static void fill_iovec(struct wrv_args *a)
|
106
|
+
{
|
107
|
+
unsigned long i;
|
108
|
+
struct iovec *curvec;
|
109
|
+
|
110
|
+
a->iov_cnt = RARRAY_LEN(a->buf);
|
111
|
+
a->batch_len = 0;
|
112
|
+
if (a->iov_cnt == 0) return;
|
113
|
+
if (a->iov_cnt > iov_max) a->iov_cnt = iov_max;
|
114
|
+
rb_str_resize(a->vec_buf, sizeof(struct iovec) * a->iov_cnt);
|
115
|
+
curvec = a->vec = (struct iovec*)RSTRING_PTR(a->vec_buf);
|
116
|
+
|
117
|
+
for (i=0; i < a->iov_cnt; i++, curvec++) {
|
118
|
+
VALUE str = rb_ary_entry(a->buf, i);
|
119
|
+
long str_len, next_len;
|
120
|
+
|
121
|
+
if (TYPE(str) != T_STRING) {
|
122
|
+
str = rb_obj_as_string(str);
|
123
|
+
rb_ary_store(a->buf, i, str);
|
124
|
+
}
|
125
|
+
|
126
|
+
str_len = RSTRING_LEN(str);
|
127
|
+
|
128
|
+
/* lets limit total memory to write,
|
129
|
+
* but always take first string */
|
130
|
+
next_len = a->batch_len + str_len;
|
131
|
+
if (i && next_len > WRITEV_MEMLIMIT) {
|
132
|
+
a->iov_cnt = i;
|
133
|
+
break;
|
134
|
+
}
|
135
|
+
a->batch_len = next_len;
|
136
|
+
|
137
|
+
curvec->iov_base = RSTRING_PTR(str);
|
138
|
+
curvec->iov_len = str_len;
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
static long trim_writev_buffer(struct wrv_args *a, long n)
|
143
|
+
{
|
144
|
+
long i;
|
145
|
+
long ary_len = RARRAY_LEN(a->buf);
|
146
|
+
|
147
|
+
if (n == (long)a->batch_len) {
|
148
|
+
i = a->iov_cnt;
|
149
|
+
n = 0;
|
150
|
+
} else {
|
151
|
+
for (i = 0; n && i < ary_len; i++) {
|
152
|
+
VALUE entry = rb_ary_entry(a->buf, i);
|
153
|
+
n -= RSTRING_LEN(entry);
|
154
|
+
if (n < 0) break;
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
/* all done */
|
159
|
+
if (i == ary_len) {
|
160
|
+
assert(n == 0 && "writev system call is broken");
|
161
|
+
a->buf = Qnil;
|
162
|
+
return 0;
|
163
|
+
}
|
164
|
+
|
165
|
+
/* partially done, remove fully-written buffers */
|
166
|
+
if (i > 0)
|
167
|
+
a->buf = rb_ary_subseq(a->buf, i, ary_len - i);
|
168
|
+
|
169
|
+
/* setup+replace partially written buffer */
|
170
|
+
if (n < 0) {
|
171
|
+
VALUE str = rb_ary_entry(a->buf, 0);
|
172
|
+
long str_len = RSTRING_LEN(str);
|
173
|
+
str = rb_str_subseq(str, str_len + n, -n);
|
174
|
+
rb_ary_store(a->buf, 0, str);
|
175
|
+
}
|
176
|
+
return RARRAY_LEN(a->buf);
|
177
|
+
}
|
178
|
+
|
179
|
+
static int writev_check(struct wrv_args *a, long n, const char *msg, int io_wait)
|
180
|
+
{
|
181
|
+
if (n >= 0) {
|
182
|
+
if (n > 0) a->something_written = 1;
|
183
|
+
return trim_writev_buffer(a, n);
|
184
|
+
} else if (n < 0) {
|
185
|
+
if (errno == EINTR) {
|
186
|
+
a->fd = my_fileno(a->io);
|
187
|
+
return -1;
|
188
|
+
}
|
189
|
+
if (errno == EAGAIN) {
|
190
|
+
if (io_wait) {
|
191
|
+
(void)kgio_call_wait_writable(a->io);
|
192
|
+
return -1;
|
193
|
+
} else if (!a->something_written) {
|
194
|
+
a->buf = sym_wait_writable;
|
195
|
+
}
|
196
|
+
return 0;
|
197
|
+
}
|
198
|
+
kgio_wr_sys_fail(msg);
|
199
|
+
}
|
200
|
+
return 0;
|
201
|
+
}
|
202
|
+
|
203
|
+
static VALUE my_writev(VALUE io, VALUE ary, int io_wait)
|
204
|
+
{
|
205
|
+
struct wrv_args a;
|
206
|
+
long n;
|
207
|
+
|
208
|
+
prepare_writev(&a, io, ary);
|
209
|
+
set_nonblocking(a.fd);
|
210
|
+
|
211
|
+
do {
|
212
|
+
fill_iovec(&a);
|
213
|
+
if (a.iov_cnt == 0)
|
214
|
+
n = 0;
|
215
|
+
else if (a.iov_cnt == 1)
|
216
|
+
n = (long)write(a.fd, a.vec[0].iov_base,
|
217
|
+
a.vec[0].iov_len);
|
218
|
+
/* for big strings use library function */
|
219
|
+
else if (USE_WRITEV &&
|
220
|
+
((a.batch_len / WRITEV_IMPL_THRESHOLD) > a.iov_cnt))
|
221
|
+
n = (long)writev(a.fd, a.vec, a.iov_cnt);
|
222
|
+
else
|
223
|
+
n = (long)custom_writev(a.fd, a.vec, a.iov_cnt,
|
224
|
+
a.batch_len);
|
225
|
+
} while (writev_check(&a, n, "writev", io_wait) != 0);
|
226
|
+
rb_str_resize(a.vec_buf, 0);
|
227
|
+
|
228
|
+
if (TYPE(a.buf) != T_SYMBOL)
|
229
|
+
kgio_autopush_write(io);
|
230
|
+
return a.buf;
|
231
|
+
}
|
232
|
+
|
233
|
+
/*
|
234
|
+
* call-seq:
|
235
|
+
*
|
236
|
+
* io.kgio_writev(array) -> nil
|
237
|
+
*
|
238
|
+
* Returns nil when the write completes.
|
239
|
+
*
|
240
|
+
* This may block and call any method defined to +kgio_wait_writable+
|
241
|
+
* for the class.
|
242
|
+
*
|
243
|
+
* Note: it uses +Array()+ semantic for converting argument, so that
|
244
|
+
* it will succeed if you pass something else.
|
245
|
+
*/
|
246
|
+
static VALUE kgio_writev(VALUE io, VALUE ary)
|
247
|
+
{
|
248
|
+
return my_writev(io, ary, 1);
|
249
|
+
}
|
250
|
+
|
251
|
+
/*
|
252
|
+
* call-seq:
|
253
|
+
*
|
254
|
+
* io.kgio_trywritev(array) -> nil, Array or :wait_writable
|
255
|
+
*
|
256
|
+
* Returns nil if the write was completed in full.
|
257
|
+
*
|
258
|
+
* Returns an Array of strings containing the unwritten portion
|
259
|
+
* if EAGAIN was encountered, but some portion was successfully written.
|
260
|
+
*
|
261
|
+
* Returns :wait_writable if EAGAIN is encountered and nothing
|
262
|
+
* was written.
|
263
|
+
*
|
264
|
+
* Note: it uses +Array()+ semantic for converting argument, so that
|
265
|
+
* it will succeed if you pass something else.
|
266
|
+
*/
|
267
|
+
static VALUE kgio_trywritev(VALUE io, VALUE ary)
|
268
|
+
{
|
269
|
+
return my_writev(io, ary, 0);
|
270
|
+
}
|
271
|
+
|
272
|
+
/*
|
273
|
+
* call-seq:
|
274
|
+
*
|
275
|
+
* Kgio.trywritev(io, array) -> nil, Array or :wait_writable
|
276
|
+
*
|
277
|
+
* Returns nil if the write was completed in full.
|
278
|
+
*
|
279
|
+
* Returns a Array of strings containing the unwritten portion if EAGAIN
|
280
|
+
* was encountered, but some portion was successfully written.
|
281
|
+
*
|
282
|
+
* Returns :wait_writable if EAGAIN is encountered and nothing
|
283
|
+
* was written.
|
284
|
+
*
|
285
|
+
* Maybe used in place of PipeMethods#kgio_trywritev for non-Kgio objects
|
286
|
+
*/
|
287
|
+
static VALUE s_trywritev(VALUE mod, VALUE io, VALUE ary)
|
288
|
+
{
|
289
|
+
return kgio_trywritev(io, ary);
|
290
|
+
}
|
291
|
+
|
292
|
+
void init_kgio_writev(void)
|
293
|
+
{
|
294
|
+
#ifdef IOV_MAX
|
295
|
+
unsigned int sys_iov_max = IOV_MAX;
|
296
|
+
#else
|
297
|
+
unsigned int sys_iov_max = sysconf(_SC_IOV_MAX);
|
298
|
+
#endif
|
299
|
+
|
300
|
+
VALUE mPipeMethods, mSocketMethods;
|
301
|
+
VALUE mKgio = rb_define_module("Kgio");
|
302
|
+
|
303
|
+
if (sys_iov_max < iov_max)
|
304
|
+
iov_max = sys_iov_max;
|
305
|
+
|
306
|
+
sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
|
307
|
+
|
308
|
+
rb_define_singleton_method(mKgio, "trywritev", s_trywritev, 2);
|
309
|
+
|
310
|
+
mPipeMethods = rb_define_module_under(mKgio, "PipeMethods");
|
311
|
+
rb_define_method(mPipeMethods, "kgio_writev", kgio_writev, 1);
|
312
|
+
rb_define_method(mPipeMethods, "kgio_trywritev", kgio_trywritev, 1);
|
313
|
+
|
314
|
+
mSocketMethods = rb_define_module_under(mKgio, "SocketMethods");
|
315
|
+
rb_define_method(mSocketMethods, "kgio_writev", kgio_writev, 1);
|
316
|
+
rb_define_method(mSocketMethods, "kgio_trywritev", kgio_trywritev, 1);
|
317
|
+
}
|
data/test/test_poll.rb
CHANGED
@@ -87,31 +87,6 @@ class TestPoll < Test::Unit::TestCase
|
|
87
87
|
trap(:USR1, orig)
|
88
88
|
end
|
89
89
|
|
90
|
-
def test_poll_EINTR_changed
|
91
|
-
ok = false
|
92
|
-
pollset = { @rd => Kgio::POLLIN }
|
93
|
-
orig = trap(:USR1) do
|
94
|
-
pollset[@wr] = Kgio::POLLOUT
|
95
|
-
ok = true
|
96
|
-
end
|
97
|
-
thr = Thread.new do
|
98
|
-
sleep 0.100
|
99
|
-
100.times do
|
100
|
-
Process.kill(:USR1, $$)
|
101
|
-
Thread.pass
|
102
|
-
end
|
103
|
-
end
|
104
|
-
t0 = Time.now
|
105
|
-
res = Kgio.poll(pollset, 1000)
|
106
|
-
diff = Time.now - t0
|
107
|
-
thr.join
|
108
|
-
assert_equal({@wr => Kgio::POLLOUT}, res)
|
109
|
-
assert diff < 1.0, "diff=#{diff}"
|
110
|
-
assert ok
|
111
|
-
ensure
|
112
|
-
trap(:USR1, orig)
|
113
|
-
end
|
114
|
-
|
115
90
|
def test_poll_signal_torture
|
116
91
|
usr1 = 0
|
117
92
|
empty = 0
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'kgio'
|
3
|
+
|
4
|
+
class TestKgioSyssend < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@host = '127.0.0.1' || ENV["TEST_HOST"]
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_syssend
|
10
|
+
srv = Kgio::TCPServer.new(@host, 0)
|
11
|
+
port = srv.addr[1]
|
12
|
+
client = TCPSocket.new(@host, port)
|
13
|
+
acc = srv.kgio_accept
|
14
|
+
th = Thread.new { client.readpartial(4) }
|
15
|
+
sleep(0.05)
|
16
|
+
assert_nil acc.kgio_syssend("HI", Socket::MSG_DONTWAIT | Socket::MSG_MORE)
|
17
|
+
assert_nil acc.kgio_syssend("HI", Socket::MSG_DONTWAIT)
|
18
|
+
assert_equal "HIHI", th.value
|
19
|
+
|
20
|
+
buf = "*" * 123
|
21
|
+
res = []
|
22
|
+
case rv = acc.kgio_syssend(buf, Socket::MSG_DONTWAIT)
|
23
|
+
when nil
|
24
|
+
when String
|
25
|
+
res << rv
|
26
|
+
when Symbol
|
27
|
+
res << rv
|
28
|
+
break
|
29
|
+
end while true
|
30
|
+
assert_equal :wait_writable, res.last
|
31
|
+
if res.size > 1
|
32
|
+
assert_kind_of String, res[-2]
|
33
|
+
else
|
34
|
+
warn "res too small"
|
35
|
+
end
|
36
|
+
|
37
|
+
# blocking
|
38
|
+
th = Thread.new { loop { acc.kgio_syssend("ZZZZ", 0) } }
|
39
|
+
assert_nil th.join(0.1)
|
40
|
+
ensure
|
41
|
+
[ srv, acc, client ].each { |io| io.close if io }
|
42
|
+
end
|
43
|
+
end if RUBY_PLATFORM =~ /linux/
|
metadata
CHANGED
@@ -1,34 +1,28 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: kgio
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.9.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 2
|
8
|
-
- 8
|
9
|
-
- 1
|
10
|
-
version: 2.8.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- kgio hackers
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2013-09-11 00:00:00 Z
|
12
|
+
date: 2014-02-04 00:00:00.000000000 Z
|
19
13
|
dependencies: []
|
14
|
+
description: ! 'kgio provides non-blocking I/O methods for Ruby without raising
|
20
15
|
|
21
|
-
description: |-
|
22
|
-
kgio provides non-blocking I/O methods for Ruby without raising
|
23
16
|
exceptions on EAGAIN and EINPROGRESS. It is intended for use with the
|
17
|
+
|
24
18
|
Unicorn and Rainbows! Rack servers, but may be used by other
|
25
|
-
|
19
|
+
|
20
|
+
applications (that run on Unix-like platforms).'
|
26
21
|
email: kgio@librelist.org
|
27
22
|
executables: []
|
28
|
-
|
29
|
-
extensions:
|
23
|
+
extensions:
|
30
24
|
- ext/kgio/extconf.rb
|
31
|
-
extra_rdoc_files:
|
25
|
+
extra_rdoc_files:
|
32
26
|
- LICENSE
|
33
27
|
- README
|
34
28
|
- TODO
|
@@ -43,10 +37,9 @@ extra_rdoc_files:
|
|
43
37
|
- ext/kgio/connect.c
|
44
38
|
- ext/kgio/kgio_ext.c
|
45
39
|
- ext/kgio/poll.c
|
46
|
-
- ext/kgio/read_write.c
|
47
40
|
- ext/kgio/wait.c
|
48
41
|
- ext/kgio/tryopen.c
|
49
|
-
files:
|
42
|
+
files:
|
50
43
|
- .document
|
51
44
|
- .gitignore
|
52
45
|
- .manifest
|
@@ -77,11 +70,13 @@ files:
|
|
77
70
|
- ext/kgio/my_fileno.h
|
78
71
|
- ext/kgio/nonblock.h
|
79
72
|
- ext/kgio/poll.c
|
80
|
-
- ext/kgio/
|
73
|
+
- ext/kgio/read.c
|
81
74
|
- ext/kgio/set_file_path.h
|
82
75
|
- ext/kgio/sock_for_fd.h
|
83
76
|
- ext/kgio/tryopen.c
|
84
77
|
- ext/kgio/wait.c
|
78
|
+
- ext/kgio/write.c
|
79
|
+
- ext/kgio/writev.c
|
85
80
|
- kgio.gemspec
|
86
81
|
- lib/kgio.rb
|
87
82
|
- pkg.mk
|
@@ -103,6 +98,7 @@ files:
|
|
103
98
|
- test/test_singleton_read_write.rb
|
104
99
|
- test/test_socket.rb
|
105
100
|
- test/test_socketpair_read_write.rb
|
101
|
+
- test/test_syssend.rb
|
106
102
|
- test/test_tcp6_client_read_server_write.rb
|
107
103
|
- test/test_tcp_client_read_server_write.rb
|
108
104
|
- test/test_tcp_connect.rb
|
@@ -116,47 +112,40 @@ files:
|
|
116
112
|
- test/test_unix_server_read_client_write.rb
|
117
113
|
homepage: http://bogomips.org/kgio/
|
118
114
|
licenses: []
|
119
|
-
|
120
115
|
post_install_message:
|
121
|
-
rdoc_options:
|
116
|
+
rdoc_options:
|
122
117
|
- -t
|
123
118
|
- kgio - kinder, gentler I/O for Ruby
|
124
119
|
- -W
|
125
120
|
- http://bogomips.org/kgio.git/tree/%s
|
126
|
-
require_paths:
|
121
|
+
require_paths:
|
127
122
|
- lib
|
128
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
124
|
none: false
|
130
|
-
requirements:
|
131
|
-
- -
|
132
|
-
- !ruby/object:Gem::Version
|
133
|
-
|
134
|
-
|
135
|
-
- 0
|
136
|
-
version: "0"
|
137
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ! '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
130
|
none: false
|
139
|
-
requirements:
|
140
|
-
- -
|
141
|
-
- !ruby/object:Gem::Version
|
142
|
-
|
143
|
-
segments:
|
144
|
-
- 0
|
145
|
-
version: "0"
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
146
135
|
requirements: []
|
147
|
-
|
148
136
|
rubyforge_project: rainbows
|
149
|
-
rubygems_version: 1.8.
|
137
|
+
rubygems_version: 1.8.23
|
150
138
|
signing_key:
|
151
139
|
specification_version: 3
|
152
140
|
summary: kinder, gentler I/O for Ruby
|
153
|
-
test_files:
|
141
|
+
test_files:
|
154
142
|
- test/test_poll.rb
|
155
143
|
- test/test_peek.rb
|
156
144
|
- test/test_socket.rb
|
157
145
|
- test/test_default_wait.rb
|
158
146
|
- test/test_no_dns_on_tcp_connect.rb
|
159
147
|
- test/test_unix_connect.rb
|
148
|
+
- test/test_syssend.rb
|
160
149
|
- test/test_pipe_read_write.rb
|
161
150
|
- test/test_unix_server.rb
|
162
151
|
- test/test_accept_flags.rb
|