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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5533173b595411c7f3c68c9aa925e18e76444660
4
- data.tar.gz: 743fdc287fcbab34e689a6e4f272f7110bb3d7aa
3
+ metadata.gz: 8b4c1e5066e4afcd3b11d893236f7fe55ca55e6d
4
+ data.tar.gz: 199526afe90a34cfd827aea17543eb12d058bbde
5
5
  SHA512:
6
- metadata.gz: 88ec86a25c45bc5a288d5f85e445a3d2cfda9611d99aec077a982e86ae0399095b98fc5cb0154896a2d6e6931b05ed7431e6d1d23e23b1758b51796dfed810bc
7
- data.tar.gz: e736aec41387787b030ae419a0650dd529c2bf000a97cd38c7bbafe6a096a56a4ec7d5a40367d3cbb6f30c96748481cdd72d4201e4a1c87dd5c408aa7a1c581b
6
+ metadata.gz: 434294bbc55400c1997545827d79647ef3ebd4179a4cd8028606efdaefadb58ad764fb9fc3b91119762727f5cf9c2e052347ecb50f602c829e083d59fdb9bf83
7
+ data.tar.gz: 84682d8e628cae20b52f1d5df0479afe3ef29cf05c7641d3302e8662ba5dd1d00a44153ec648878325d7e950994d770d532f6b87f94929141a73e13fd03775bf
data/.document CHANGED
@@ -7,6 +7,7 @@ ISSUES
7
7
  HACKING
8
8
  lib
9
9
  ext/kgio/accept.c
10
+ ext/kgio/autopush.c
10
11
  ext/kgio/connect.c
11
12
  ext/kgio/kgio_ext.c
12
13
  ext/kgio/poll.c
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v2.10.0
4
+ DEF_VER=v2.11.0
5
5
 
6
6
  LF='
7
7
  '
data/TODO CHANGED
@@ -1,3 +1,2 @@
1
- * remove old autopush interface (for kgio 3.x)
2
1
  * obsolete kgio by improving *_nonblock methods in Ruby itself
3
- (Mostly done Ruby 2.3.0)
2
+ (Done for *_nonblock in Ruby 2.3.x, not sure for poll and writev support)
@@ -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,
@@ -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 */
@@ -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))
@@ -95,6 +95,7 @@ void Init_kgio_ext(void)
95
95
  init_kgio_writev();
96
96
  init_kgio_connect();
97
97
  init_kgio_accept();
98
+ init_kgio_autopush();
98
99
  init_kgio_poll();
99
100
  init_kgio_tryopen();
100
101
  }
@@ -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)
@@ -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
 
@@ -249,6 +249,8 @@ static VALUE my_writev(VALUE io, VALUE ary, int io_wait)
249
249
  } while (writev_check(&a, n, "writev", io_wait) != 0);
250
250
  rb_str_resize(a.vec_buf, 0);
251
251
 
252
+ if (TYPE(a.buf) != T_SYMBOL)
253
+ kgio_autopush_write(io);
252
254
  return a.buf;
253
255
  }
254
256
 
@@ -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'
@@ -7,7 +7,12 @@ $-w = true
7
7
  require 'kgio'
8
8
 
9
9
  module LibReadWriteTest
10
- RANDOM_BLOB = File.open("/dev/urandom") { |fp| fp.read(10 * 1024 * 1024) }
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 = "." * 1024 * 1024 * 10
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 = ["." * 1024] * 1024 * 10
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?
@@ -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
- def test_compatibility
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.10.0
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: 2015-09-06 00:00:00.000000000 Z
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.5.0
157
+ rubygems_version: 2.6.8
156
158
  signing_key:
157
159
  specification_version: 4
158
160
  summary: kinder, gentler I/O for Ruby