kgio 2.10.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
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