kgio 2.10.0 → 2.11.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.
- checksums.yaml +4 -4
- data/.document +1 -0
- data/GIT-VERSION-GEN +1 -1
- data/TODO +1 -2
- data/ext/kgio/accept.c +7 -0
- data/ext/kgio/autopush.c +252 -0
- data/ext/kgio/kgio.h +12 -0
- data/ext/kgio/kgio_ext.c +1 -0
- data/ext/kgio/read.c +8 -0
- data/ext/kgio/write.c +4 -0
- data/ext/kgio/writev.c +2 -0
- data/lib/kgio.rb +0 -10
- data/test/lib_read_write.rb +8 -3
- data/test/test_autopush.rb +157 -3
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b4c1e5066e4afcd3b11d893236f7fe55ca55e6d
|
4
|
+
data.tar.gz: 199526afe90a34cfd827aea17543eb12d058bbde
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 434294bbc55400c1997545827d79647ef3ebd4179a4cd8028606efdaefadb58ad764fb9fc3b91119762727f5cf9c2e052347ecb50f602c829e083d59fdb9bf83
|
7
|
+
data.tar.gz: 84682d8e628cae20b52f1d5df0479afe3ef29cf05c7641d3302e8662ba5dd1d00a44153ec648878325d7e950994d770d532f6b87f94929141a73e13fd03775bf
|
data/.document
CHANGED
data/GIT-VERSION-GEN
CHANGED
data/TODO
CHANGED
data/ext/kgio/accept.c
CHANGED
@@ -160,6 +160,12 @@ static VALUE in_addr_set(VALUE io, struct sockaddr_storage *addr, socklen_t len)
|
|
160
160
|
return rb_ivar_set(io, iv_kgio_addr, host);
|
161
161
|
}
|
162
162
|
|
163
|
+
#if defined(__linux__)
|
164
|
+
# define post_accept kgio_autopush_accept
|
165
|
+
#else
|
166
|
+
# define post_accept(a,b) for(;0;)
|
167
|
+
#endif
|
168
|
+
|
163
169
|
static VALUE
|
164
170
|
my_accept(struct accept_args *a, int force_nonblock)
|
165
171
|
{
|
@@ -205,6 +211,7 @@ retry:
|
|
205
211
|
}
|
206
212
|
}
|
207
213
|
client_io = sock_for_fd(a->accepted_class, client_fd);
|
214
|
+
post_accept(a->accept_io, client_io);
|
208
215
|
|
209
216
|
if (a->addr)
|
210
217
|
in_addr_set(client_io,
|
data/ext/kgio/autopush.c
ADDED
@@ -0,0 +1,252 @@
|
|
1
|
+
/*
|
2
|
+
* We use a very basic strategy to use TCP_CORK semantics optimally
|
3
|
+
* in most TCP servers: On corked sockets, we will uncork on recv()
|
4
|
+
* if there was a previous send(). Otherwise we do not fiddle
|
5
|
+
* with TCP_CORK at all.
|
6
|
+
*
|
7
|
+
* Under Linux, we can rely on TCP_CORK being inherited in an
|
8
|
+
* accept()-ed client socket so we can avoid syscalls for each
|
9
|
+
* accept()-ed client if we know the accept() socket corks.
|
10
|
+
*
|
11
|
+
* This module does NOTHING for client TCP sockets, we only deal
|
12
|
+
* with accept()-ed sockets right now.
|
13
|
+
*/
|
14
|
+
|
15
|
+
#include "kgio.h"
|
16
|
+
#include "my_fileno.h"
|
17
|
+
#include <netinet/tcp.h>
|
18
|
+
|
19
|
+
/*
|
20
|
+
* As of FreeBSD 4.5, TCP_NOPUSH == TCP_CORK
|
21
|
+
* ref: http://dotat.at/writing/nopush.html
|
22
|
+
* We won't care for older FreeBSD since nobody runs Ruby on them...
|
23
|
+
*/
|
24
|
+
#ifdef TCP_CORK
|
25
|
+
# define KGIO_NOPUSH TCP_CORK
|
26
|
+
#elif defined(TCP_NOPUSH)
|
27
|
+
# define KGIO_NOPUSH TCP_NOPUSH
|
28
|
+
#endif
|
29
|
+
|
30
|
+
#ifdef KGIO_NOPUSH
|
31
|
+
static ID id_autopush_state;
|
32
|
+
static int enabled = 1;
|
33
|
+
|
34
|
+
enum autopush_state {
|
35
|
+
AUTOPUSH_STATE_ACCEPTOR_IGNORE = -1,
|
36
|
+
AUTOPUSH_STATE_IGNORE = 0,
|
37
|
+
AUTOPUSH_STATE_WRITER = 1,
|
38
|
+
AUTOPUSH_STATE_WRITTEN = 2,
|
39
|
+
AUTOPUSH_STATE_ACCEPTOR = 3
|
40
|
+
};
|
41
|
+
|
42
|
+
#if defined(R_CAST) && \
|
43
|
+
defined(HAVE_TYPE_STRUCT_RFILE) && \
|
44
|
+
defined(HAVE_TYPE_STRUCT_ROBJECT) && \
|
45
|
+
((SIZEOF_STRUCT_RFILE + SIZEOF_INT) <= (SIZEOF_STRUCT_ROBJECT))
|
46
|
+
|
47
|
+
struct AutopushSocket {
|
48
|
+
struct RFile rfile;
|
49
|
+
enum autopush_state autopush_state;
|
50
|
+
};
|
51
|
+
|
52
|
+
static enum autopush_state state_get(VALUE io)
|
53
|
+
{
|
54
|
+
return ((struct AutopushSocket *)(io))->autopush_state;
|
55
|
+
}
|
56
|
+
|
57
|
+
static void state_set(VALUE io, enum autopush_state state)
|
58
|
+
{
|
59
|
+
((struct AutopushSocket *)(io))->autopush_state = state;
|
60
|
+
}
|
61
|
+
#else
|
62
|
+
static enum autopush_state state_get(VALUE io)
|
63
|
+
{
|
64
|
+
VALUE val;
|
65
|
+
|
66
|
+
if (rb_ivar_defined(io, id_autopush_state) == Qfalse)
|
67
|
+
return AUTOPUSH_STATE_IGNORE;
|
68
|
+
val = rb_ivar_get(io, id_autopush_state);
|
69
|
+
|
70
|
+
return (enum autopush_state)NUM2INT(val);
|
71
|
+
}
|
72
|
+
|
73
|
+
static void state_set(VALUE io, enum autopush_state state)
|
74
|
+
{
|
75
|
+
rb_ivar_set(io, id_autopush_state, INT2NUM(state));
|
76
|
+
}
|
77
|
+
#endif /* IVAR fallback */
|
78
|
+
|
79
|
+
static enum autopush_state detect_acceptor_state(VALUE io);
|
80
|
+
static void push_pending_data(VALUE io);
|
81
|
+
|
82
|
+
/*
|
83
|
+
* call-seq:
|
84
|
+
* Kgio.autopush? -> true or false
|
85
|
+
*
|
86
|
+
* Returns whether or not autopush is enabled.
|
87
|
+
*
|
88
|
+
* Only available on systems with TCP_CORK (Linux) or
|
89
|
+
* TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
|
90
|
+
*/
|
91
|
+
static VALUE s_get_autopush(VALUE self)
|
92
|
+
{
|
93
|
+
return enabled ? Qtrue : Qfalse;
|
94
|
+
}
|
95
|
+
|
96
|
+
/*
|
97
|
+
* call-seq:
|
98
|
+
* Kgio.autopush = true
|
99
|
+
* Kgio.autopush = false
|
100
|
+
*
|
101
|
+
* Enables or disables autopush for sockets created with kgio_accept
|
102
|
+
* and kgio_tryaccept methods. Autopush relies on TCP_CORK/TCP_NOPUSH
|
103
|
+
* being enabled on the listen socket.
|
104
|
+
*
|
105
|
+
* Only available on systems with TCP_CORK (Linux) or
|
106
|
+
* TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
|
107
|
+
*
|
108
|
+
* Please do not use this (or kgio at all) in new code. Under Linux,
|
109
|
+
* use MSG_MORE, instead, as it requires fewer syscalls. Users of
|
110
|
+
* other systems are encouraged to add MSG_MORE support to their
|
111
|
+
* favorite OS.
|
112
|
+
*/
|
113
|
+
static VALUE s_set_autopush(VALUE self, VALUE val)
|
114
|
+
{
|
115
|
+
enabled = RTEST(val);
|
116
|
+
|
117
|
+
return val;
|
118
|
+
}
|
119
|
+
|
120
|
+
/*
|
121
|
+
* call-seq:
|
122
|
+
*
|
123
|
+
* io.kgio_autopush? -> true or false
|
124
|
+
*
|
125
|
+
* Returns the current autopush state of the Kgio::SocketMethods-enabled
|
126
|
+
* socket.
|
127
|
+
*
|
128
|
+
* Only available on systems with TCP_CORK (Linux) or
|
129
|
+
* TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
|
130
|
+
*/
|
131
|
+
static VALUE autopush_get(VALUE io)
|
132
|
+
{
|
133
|
+
return state_get(io) <= 0 ? Qfalse : Qtrue;
|
134
|
+
}
|
135
|
+
|
136
|
+
/*
|
137
|
+
* call-seq:
|
138
|
+
*
|
139
|
+
* io.kgio_autopush = true
|
140
|
+
* io.kgio_autopush = false
|
141
|
+
*
|
142
|
+
* Enables or disables autopush on any given Kgio::SocketMethods-capable
|
143
|
+
* IO object. This does NOT enable or disable TCP_NOPUSH/TCP_CORK right
|
144
|
+
* away, that must be done with IO.setsockopt
|
145
|
+
*
|
146
|
+
* Only available on systems with TCP_CORK (Linux) or
|
147
|
+
* TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
|
148
|
+
*/
|
149
|
+
static VALUE autopush_set(VALUE io, VALUE vbool)
|
150
|
+
{
|
151
|
+
if (RTEST(vbool))
|
152
|
+
state_set(io, AUTOPUSH_STATE_WRITER);
|
153
|
+
else
|
154
|
+
state_set(io, AUTOPUSH_STATE_IGNORE);
|
155
|
+
return vbool;
|
156
|
+
}
|
157
|
+
|
158
|
+
void init_kgio_autopush(void)
|
159
|
+
{
|
160
|
+
VALUE mKgio = rb_define_module("Kgio");
|
161
|
+
VALUE tmp;
|
162
|
+
|
163
|
+
rb_define_singleton_method(mKgio, "autopush?", s_get_autopush, 0);
|
164
|
+
rb_define_singleton_method(mKgio, "autopush=", s_set_autopush, 1);
|
165
|
+
|
166
|
+
tmp = rb_define_module_under(mKgio, "SocketMethods");
|
167
|
+
rb_define_method(tmp, "kgio_autopush=", autopush_set, 1);
|
168
|
+
rb_define_method(tmp, "kgio_autopush?", autopush_get, 0);
|
169
|
+
|
170
|
+
id_autopush_state = rb_intern("@kgio_autopush_state");
|
171
|
+
}
|
172
|
+
|
173
|
+
/*
|
174
|
+
* called after a successful write, just mark that we've put something
|
175
|
+
* in the skb and will need to uncork on the next write.
|
176
|
+
*/
|
177
|
+
void kgio_autopush_send(VALUE io)
|
178
|
+
{
|
179
|
+
if (state_get(io) == AUTOPUSH_STATE_WRITER)
|
180
|
+
state_set(io, AUTOPUSH_STATE_WRITTEN);
|
181
|
+
}
|
182
|
+
|
183
|
+
/* called on successful accept() */
|
184
|
+
void kgio_autopush_accept(VALUE accept_io, VALUE client_io)
|
185
|
+
{
|
186
|
+
enum autopush_state acceptor_state;
|
187
|
+
|
188
|
+
if (!enabled)
|
189
|
+
return;
|
190
|
+
acceptor_state = state_get(accept_io);
|
191
|
+
if (acceptor_state == AUTOPUSH_STATE_IGNORE)
|
192
|
+
acceptor_state = detect_acceptor_state(accept_io);
|
193
|
+
if (acceptor_state == AUTOPUSH_STATE_ACCEPTOR)
|
194
|
+
state_set(client_io, AUTOPUSH_STATE_WRITER);
|
195
|
+
else
|
196
|
+
state_set(client_io, AUTOPUSH_STATE_IGNORE);
|
197
|
+
}
|
198
|
+
|
199
|
+
void kgio_autopush_recv(VALUE io)
|
200
|
+
{
|
201
|
+
if (enabled && (state_get(io) == AUTOPUSH_STATE_WRITTEN)) {
|
202
|
+
push_pending_data(io);
|
203
|
+
state_set(io, AUTOPUSH_STATE_WRITER);
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
207
|
+
static enum autopush_state detect_acceptor_state(VALUE io)
|
208
|
+
{
|
209
|
+
int corked = 0;
|
210
|
+
int fd = my_fileno(io);
|
211
|
+
socklen_t optlen = sizeof(int);
|
212
|
+
enum autopush_state state;
|
213
|
+
|
214
|
+
if (getsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &corked, &optlen) != 0) {
|
215
|
+
if (errno != EOPNOTSUPP)
|
216
|
+
rb_sys_fail("getsockopt(TCP_CORK/TCP_NOPUSH)");
|
217
|
+
errno = 0;
|
218
|
+
state = AUTOPUSH_STATE_ACCEPTOR_IGNORE;
|
219
|
+
} else if (corked) {
|
220
|
+
state = AUTOPUSH_STATE_ACCEPTOR;
|
221
|
+
} else {
|
222
|
+
state = AUTOPUSH_STATE_ACCEPTOR_IGNORE;
|
223
|
+
}
|
224
|
+
state_set(io, state);
|
225
|
+
|
226
|
+
return state;
|
227
|
+
}
|
228
|
+
|
229
|
+
/*
|
230
|
+
* checks to see if we've written anything since the last recv()
|
231
|
+
* If we have, uncork the socket and immediately recork it.
|
232
|
+
*/
|
233
|
+
static void push_pending_data(VALUE io)
|
234
|
+
{
|
235
|
+
int optval = 0;
|
236
|
+
const socklen_t optlen = sizeof(int);
|
237
|
+
const int fd = my_fileno(io);
|
238
|
+
|
239
|
+
if (setsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &optval, optlen) != 0)
|
240
|
+
rb_sys_fail("setsockopt(TCP_CORK/TCP_NOPUSH, 0)");
|
241
|
+
/* immediately recork */
|
242
|
+
optval = 1;
|
243
|
+
if (setsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &optval, optlen) != 0)
|
244
|
+
rb_sys_fail("setsockopt(TCP_CORK/TCP_NOPUSH, 1)");
|
245
|
+
}
|
246
|
+
#else /* !KGIO_NOPUSH */
|
247
|
+
void kgio_autopush_recv(VALUE io){}
|
248
|
+
void kgio_autopush_send(VALUE io){}
|
249
|
+
void init_kgio_autopush(void)
|
250
|
+
{
|
251
|
+
}
|
252
|
+
#endif /* ! KGIO_NOPUSH */
|
data/ext/kgio/kgio.h
CHANGED
@@ -29,9 +29,14 @@ void init_kgio_write(void);
|
|
29
29
|
void init_kgio_writev(void);
|
30
30
|
void init_kgio_accept(void);
|
31
31
|
void init_kgio_connect(void);
|
32
|
+
void init_kgio_autopush(void);
|
32
33
|
void init_kgio_poll(void);
|
33
34
|
void init_kgio_tryopen(void);
|
34
35
|
|
36
|
+
void kgio_autopush_accept(VALUE, VALUE);
|
37
|
+
void kgio_autopush_recv(VALUE);
|
38
|
+
void kgio_autopush_send(VALUE);
|
39
|
+
|
35
40
|
VALUE kgio_call_wait_writable(VALUE io);
|
36
41
|
VALUE kgio_call_wait_readable(VALUE io);
|
37
42
|
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && defined(HAVE_RUBY_THREAD_H)
|
@@ -85,6 +90,13 @@ NORETURN(void kgio_rd_sys_fail(const char *));
|
|
85
90
|
# define USE_MSG_DONTWAIT
|
86
91
|
# endif
|
87
92
|
|
93
|
+
#ifdef USE_MSG_DONTWAIT
|
94
|
+
/* we don't need these variants, we call kgio_autopush_send/recv directly */
|
95
|
+
static inline void kgio_autopush_write(VALUE io) { }
|
96
|
+
#else
|
97
|
+
static inline void kgio_autopush_write(VALUE io) { kgio_autopush_send(io); }
|
98
|
+
#endif
|
99
|
+
|
88
100
|
/* prefer rb_str_subseq because we don't use negative offsets */
|
89
101
|
#ifndef HAVE_RB_STR_SUBSEQ
|
90
102
|
#define MY_STR_SUBSEQ(str,beg,len) rb_str_substr((str),(beg),(len))
|
data/ext/kgio/kgio_ext.c
CHANGED
data/ext/kgio/read.c
CHANGED
@@ -7,8 +7,13 @@ static VALUE sym_wait_readable;
|
|
7
7
|
|
8
8
|
#ifdef USE_MSG_DONTWAIT
|
9
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
|
+
|
10
14
|
#else
|
11
15
|
static const int peek_flags = MSG_PEEK;
|
16
|
+
static inline void kgio_autopush_read(VALUE io) { kgio_autopush_recv(io); }
|
12
17
|
#endif
|
13
18
|
|
14
19
|
struct rd_args {
|
@@ -80,6 +85,7 @@ static VALUE my_read(int io_wait, int argc, VALUE *argv, VALUE io)
|
|
80
85
|
long n;
|
81
86
|
|
82
87
|
prepare_read(&a, argc, argv, io);
|
88
|
+
kgio_autopush_read(io);
|
83
89
|
|
84
90
|
if (a.len > 0) {
|
85
91
|
set_nonblocking(a.fd);
|
@@ -152,6 +158,7 @@ static VALUE my_recv(int io_wait, int argc, VALUE *argv, VALUE io)
|
|
152
158
|
long n;
|
153
159
|
|
154
160
|
prepare_read(&a, argc, argv, io);
|
161
|
+
kgio_autopush_recv(io);
|
155
162
|
|
156
163
|
if (a.len > 0) {
|
157
164
|
retry:
|
@@ -205,6 +212,7 @@ static VALUE my_peek(int io_wait, int argc, VALUE *argv, VALUE io)
|
|
205
212
|
long n;
|
206
213
|
|
207
214
|
prepare_read(&a, argc, argv, io);
|
215
|
+
kgio_autopush_recv(io);
|
208
216
|
|
209
217
|
if (a.len > 0) {
|
210
218
|
if (peek_flags == MSG_PEEK)
|
data/ext/kgio/write.c
CHANGED
@@ -72,6 +72,8 @@ retry:
|
|
72
72
|
n = (long)write(a.fd, a.ptr, a.len);
|
73
73
|
if (write_check(&a, n, "write", io_wait) != 0)
|
74
74
|
goto retry;
|
75
|
+
if (TYPE(a.buf) != T_SYMBOL)
|
76
|
+
kgio_autopush_write(io);
|
75
77
|
return a.buf;
|
76
78
|
}
|
77
79
|
|
@@ -124,6 +126,8 @@ retry:
|
|
124
126
|
n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
|
125
127
|
if (write_check(&a, n, "send", io_wait) != 0)
|
126
128
|
goto retry;
|
129
|
+
if (TYPE(a.buf) != T_SYMBOL)
|
130
|
+
kgio_autopush_send(io);
|
127
131
|
return a.buf;
|
128
132
|
}
|
129
133
|
|
data/ext/kgio/writev.c
CHANGED
data/lib/kgio.rb
CHANGED
@@ -16,16 +16,6 @@ module Kgio
|
|
16
16
|
# PipeMethods#kgio_trywrite and SocketMethods#kgio_trywrite will return
|
17
17
|
# :wait_writable when waiting for a read is required.
|
18
18
|
WaitWritable = :wait_writable
|
19
|
-
|
20
|
-
# autopush is no-op nowadays
|
21
|
-
@autopush = false
|
22
|
-
|
23
|
-
class << self
|
24
|
-
attr_accessor :autopush # :nodoc:
|
25
|
-
def autopush? # :nodoc:
|
26
|
-
!!@autopush
|
27
|
-
end
|
28
|
-
end
|
29
19
|
end
|
30
20
|
|
31
21
|
require 'kgio_ext'
|
data/test/lib_read_write.rb
CHANGED
@@ -7,7 +7,12 @@ $-w = true
|
|
7
7
|
require 'kgio'
|
8
8
|
|
9
9
|
module LibReadWriteTest
|
10
|
-
RANDOM_BLOB = File.open("/dev/urandom")
|
10
|
+
RANDOM_BLOB = File.open("/dev/urandom") do |fp|
|
11
|
+
nr = 31
|
12
|
+
buf = fp.read(nr)
|
13
|
+
# get roughly a 20MB block of random data
|
14
|
+
(buf * (20 * 1024 * 1024 / nr)) + (buf * rand(123))
|
15
|
+
end
|
11
16
|
|
12
17
|
def teardown
|
13
18
|
@rd.close if defined?(@rd) && ! @rd.closed?
|
@@ -369,7 +374,7 @@ module LibReadWriteTest
|
|
369
374
|
@nr += 1
|
370
375
|
IO.select(nil, [self])
|
371
376
|
end
|
372
|
-
buf =
|
377
|
+
buf = RANDOM_BLOB
|
373
378
|
thr = Thread.new { @wr.kgio_write(buf) }
|
374
379
|
Thread.pass until thr.stop?
|
375
380
|
readed = @rd.read(buf.size)
|
@@ -385,7 +390,7 @@ module LibReadWriteTest
|
|
385
390
|
@nr += 1
|
386
391
|
IO.select(nil, [self])
|
387
392
|
end
|
388
|
-
buf = [
|
393
|
+
buf = [ RANDOM_BLOB, RANDOM_BLOB ]
|
389
394
|
buf_size = buf.inject(0){|c, s| c + s.size}
|
390
395
|
thr = Thread.new { @wr.kgio_writev(buf) }
|
391
396
|
Thread.pass until thr.stop?
|
data/test/test_autopush.rb
CHANGED
@@ -1,11 +1,165 @@
|
|
1
|
+
require 'tempfile'
|
1
2
|
require 'test/unit'
|
3
|
+
begin
|
4
|
+
$-w = false
|
5
|
+
RUBY_PLATFORM =~ /linux/ and require 'strace'
|
6
|
+
rescue LoadError
|
7
|
+
end
|
8
|
+
$-w = true
|
2
9
|
require 'kgio'
|
3
10
|
|
4
11
|
class TestAutopush < Test::Unit::TestCase
|
5
|
-
|
12
|
+
TCP_CORK = 3
|
13
|
+
TCP_NOPUSH = 4
|
14
|
+
|
15
|
+
def setup
|
16
|
+
Kgio.autopush = false
|
17
|
+
assert_equal false, Kgio.autopush?
|
18
|
+
|
19
|
+
@host = ENV["TEST_HOST"] || '127.0.0.1'
|
20
|
+
@srv = Kgio::TCPServer.new(@host, 0)
|
21
|
+
RUBY_PLATFORM =~ /linux/ and
|
22
|
+
@srv.setsockopt(Socket::IPPROTO_TCP, TCP_CORK, 1)
|
23
|
+
RUBY_PLATFORM =~ /freebsd/ and
|
24
|
+
@srv.setsockopt(Socket::IPPROTO_TCP, TCP_NOPUSH, 1)
|
25
|
+
@port = @srv.addr[1]
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_autopush_accessors
|
29
|
+
Kgio.autopush = true
|
30
|
+
opt = RUBY_PLATFORM =~ /freebsd/ ? TCP_NOPUSH : TCP_CORK
|
31
|
+
s = Kgio::TCPSocket.new(@host, @port)
|
32
|
+
assert_equal 0, s.getsockopt(Socket::IPPROTO_TCP, opt).unpack('i')[0]
|
33
|
+
assert ! s.kgio_autopush?
|
34
|
+
s.kgio_autopush = true
|
35
|
+
assert s.kgio_autopush?
|
36
|
+
s.kgio_write 'asdf'
|
37
|
+
assert_equal :wait_readable, s.kgio_tryread(1)
|
38
|
+
assert s.kgio_autopush?
|
39
|
+
val = s.getsockopt(Socket::IPPROTO_TCP, opt).unpack('i')[0]
|
40
|
+
assert_operator val, :>, 0, "#{opt}=#{val} (#{RUBY_PLATFORM})"
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_autopush_true_unix
|
44
|
+
Kgio.autopush = true
|
45
|
+
tmp = Tempfile.new('kgio_unix')
|
46
|
+
@path = tmp.path
|
47
|
+
tmp.close!
|
48
|
+
@srv = Kgio::UNIXServer.new(@path)
|
49
|
+
@rd = Kgio::UNIXSocket.new(@path)
|
50
|
+
t0 = nil
|
51
|
+
if defined?(Strace)
|
52
|
+
io, err = Strace.me { @wr = @srv.kgio_accept }
|
53
|
+
assert_nil err
|
54
|
+
rc = nil
|
55
|
+
io, err = Strace.me {
|
56
|
+
t0 = Time.now
|
57
|
+
@wr.kgio_write "HI\n"
|
58
|
+
rc = @wr.kgio_tryread 666
|
59
|
+
}
|
60
|
+
assert_nil err
|
61
|
+
lines = io.readlines
|
62
|
+
assert lines.grep(/TCP_CORK/).empty?, lines.inspect
|
63
|
+
else
|
64
|
+
@wr = @srv.kgio_accept
|
65
|
+
t0 = Time.now
|
66
|
+
@wr.kgio_write "HI\n"
|
67
|
+
rc = @wr.kgio_tryread 666
|
68
|
+
end
|
69
|
+
assert_equal "HI\n", @rd.kgio_read(3)
|
70
|
+
diff = Time.now - t0
|
71
|
+
assert(diff < 0.200, "nopush on UNIX sockets? diff=#{diff} > 200ms")
|
72
|
+
assert_equal :wait_readable, rc
|
73
|
+
ensure
|
74
|
+
File.unlink(@path) rescue nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_autopush_false
|
78
|
+
Kgio.autopush = nil
|
79
|
+
assert_equal false, Kgio.autopush?
|
80
|
+
|
81
|
+
@wr = Kgio::TCPSocket.new(@host, @port)
|
82
|
+
if defined?(Strace)
|
83
|
+
io, err = Strace.me { @rd = @srv.kgio_accept }
|
84
|
+
assert_nil err
|
85
|
+
lines = io.readlines
|
86
|
+
assert lines.grep(/TCP_CORK/).empty?, lines.inspect
|
87
|
+
assert_equal 1, @rd.getsockopt(Socket::SOL_TCP, TCP_CORK).unpack("i")[0]
|
88
|
+
else
|
89
|
+
@rd = @srv.kgio_accept
|
90
|
+
end
|
91
|
+
|
92
|
+
rbuf = "..."
|
93
|
+
t0 = Time.now
|
94
|
+
@rd.kgio_write "HI\n"
|
95
|
+
@wr.kgio_read(3, rbuf)
|
96
|
+
diff = Time.now - t0
|
97
|
+
assert(diff >= 0.190, "nopush broken? diff=#{diff} > 200ms")
|
98
|
+
assert_equal "HI\n", rbuf
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_autopush_true
|
6
102
|
Kgio.autopush = true
|
7
103
|
assert_equal true, Kgio.autopush?
|
104
|
+
@wr = Kgio::TCPSocket.new(@host, @port)
|
105
|
+
|
106
|
+
if defined?(Strace)
|
107
|
+
io, err = Strace.me { @rd = @srv.kgio_accept }
|
108
|
+
assert_nil err
|
109
|
+
lines = io.readlines
|
110
|
+
assert_equal 1, lines.grep(/TCP_CORK/).size, lines.inspect
|
111
|
+
assert_equal 1, @rd.getsockopt(Socket::SOL_TCP, TCP_CORK).unpack("i")[0]
|
112
|
+
else
|
113
|
+
@rd = @srv.kgio_accept
|
114
|
+
end
|
115
|
+
|
116
|
+
@wr.write "HI\n"
|
117
|
+
rbuf = ""
|
118
|
+
if defined?(Strace)
|
119
|
+
io, err = Strace.me { @rd.kgio_read(3, rbuf) }
|
120
|
+
assert_nil err
|
121
|
+
lines = io.readlines
|
122
|
+
assert lines.grep(/TCP_CORK/).empty?, lines.inspect
|
123
|
+
assert_equal "HI\n", rbuf
|
124
|
+
else
|
125
|
+
assert_equal "HI\n", @rd.kgio_read(3, rbuf)
|
126
|
+
end
|
127
|
+
|
128
|
+
t0 = Time.now
|
129
|
+
@rd.kgio_write "HI2U2\n"
|
130
|
+
@rd.kgio_write "HOW\n"
|
131
|
+
rc = false
|
132
|
+
|
133
|
+
if defined?(Strace)
|
134
|
+
io, err = Strace.me { rc = @rd.kgio_tryread(666) }
|
135
|
+
else
|
136
|
+
rc = @rd.kgio_tryread(666)
|
137
|
+
end
|
138
|
+
|
139
|
+
@wr.readpartial(666, rbuf)
|
140
|
+
rbuf == "HI2U2\nHOW\n" or warn "rbuf=#{rbuf.inspect} looking bad?"
|
141
|
+
diff = Time.now - t0
|
142
|
+
assert(diff < 0.200, "time diff=#{diff} >= 200ms")
|
143
|
+
assert_equal :wait_readable, rc
|
144
|
+
if defined?(Strace)
|
145
|
+
assert_nil err
|
146
|
+
lines = io.readlines
|
147
|
+
assert_equal 2, lines.grep(/TCP_CORK/).size, lines.inspect
|
148
|
+
end
|
149
|
+
@wr.close
|
150
|
+
@rd.close
|
151
|
+
|
152
|
+
@wr = Kgio::TCPSocket.new(@host, @port)
|
153
|
+
if defined?(Strace)
|
154
|
+
io, err = Strace.me { @rd = @srv.kgio_accept }
|
155
|
+
assert_nil err
|
156
|
+
lines = io.readlines
|
157
|
+
assert lines.grep(/TCP_CORK/).empty?,"optimization fail: #{lines.inspect}"
|
158
|
+
assert_equal 1, @rd.getsockopt(Socket::SOL_TCP, TCP_CORK).unpack("i")[0]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def teardown
|
8
163
|
Kgio.autopush = false
|
9
|
-
assert_equal false, Kgio.autopush?
|
10
164
|
end
|
11
|
-
end
|
165
|
+
end if RUBY_PLATFORM =~ /linux|freebsd/
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kgio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kgio hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-12-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: olddoc
|
@@ -57,6 +57,7 @@ extra_rdoc_files:
|
|
57
57
|
- HACKING
|
58
58
|
- lib/kgio.rb
|
59
59
|
- ext/kgio/accept.c
|
60
|
+
- ext/kgio/autopush.c
|
60
61
|
- ext/kgio/connect.c
|
61
62
|
- ext/kgio/kgio_ext.c
|
62
63
|
- ext/kgio/poll.c
|
@@ -82,6 +83,7 @@ files:
|
|
82
83
|
- archive/slrnpull.conf
|
83
84
|
- ext/kgio/accept.c
|
84
85
|
- ext/kgio/ancient_ruby.h
|
86
|
+
- ext/kgio/autopush.c
|
85
87
|
- ext/kgio/blocking_io_region.h
|
86
88
|
- ext/kgio/broken_system_compat.h
|
87
89
|
- ext/kgio/connect.c
|
@@ -152,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
154
|
version: '0'
|
153
155
|
requirements: []
|
154
156
|
rubyforge_project:
|
155
|
-
rubygems_version: 2.
|
157
|
+
rubygems_version: 2.6.8
|
156
158
|
signing_key:
|
157
159
|
specification_version: 4
|
158
160
|
summary: kinder, gentler I/O for Ruby
|