kgio 2.9.3 → 2.10.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: b0740f772bbf0d1b65ee40ad553e466f396c1adc
4
- data.tar.gz: 6e7de48ded07946409a01acd5d377127e61630cb
3
+ metadata.gz: 5533173b595411c7f3c68c9aa925e18e76444660
4
+ data.tar.gz: 743fdc287fcbab34e689a6e4f272f7110bb3d7aa
5
5
  SHA512:
6
- metadata.gz: 4cd8f71b71d6c85f934b4a2310834cc341c138bb11da67ef3fb2d17d123fa8d8c5e17f9fdd67ec3398491648a4c3d6ab1872b4195f4c4d6a36019a620afdbe16
7
- data.tar.gz: 18055348aa99100d39c5277a86e2b572b62ea87b153c6fad4065d3c31fdb0720319094c5aa1ff539ec43beb47f1bc94be7fc293f4f7bf7f710861a10b2a5d581
6
+ metadata.gz: 88ec86a25c45bc5a288d5f85e445a3d2cfda9611d99aec077a982e86ae0399095b98fc5cb0154896a2d6e6931b05ed7431e6d1d23e23b1758b51796dfed810bc
7
+ data.tar.gz: e736aec41387787b030ae419a0650dd529c2bf000a97cd38c7bbafe6a096a56a4ec7d5a40367d3cbb6f30c96748481cdd72d4201e4a1c87dd5c408aa7a1c581b
data/.document CHANGED
@@ -7,7 +7,6 @@ ISSUES
7
7
  HACKING
8
8
  lib
9
9
  ext/kgio/accept.c
10
- ext/kgio/autopush.c
11
10
  ext/kgio/connect.c
12
11
  ext/kgio/kgio_ext.c
13
12
  ext/kgio/poll.c
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v2.9.3
4
+ DEF_VER=v2.10.0
5
5
 
6
6
  LF='
7
7
  '
data/HACKING CHANGED
@@ -9,20 +9,19 @@ Please wrap documentation at 72 characters-per-line or less (long URLs
9
9
  are exempt) so it is comfortably readable from terminals.
10
10
 
11
11
  When referencing mailing list posts, use
12
- "http://mid.gmane.org/$MESSAGE_ID" if possible since the Message-ID
13
- remains searchable even if Gmane becomes unavailable.
12
+ "http://bogomips.org/kgio-public/$MESSAGE_ID/" if possible since the
13
+ Message-ID remains searchable even if the archive becomes unavailable.
14
14
 
15
15
  === Code Compatibility
16
16
 
17
- We target Ruby 1.8.6+, 1.9.1+ and Rubinius 1.1+ and their
18
- respective C APIs.
17
+ We target mainline Ruby 1.9.3 and later.
19
18
 
20
19
  All of our C code should be compatible with all reasonably modern Unices
21
20
  and should run on compilers supported by the versions of Ruby we target.
22
21
 
23
- We will NEVER directly support non-Free platforms under any circumstances.
22
+ We will NEVER support non-Free platforms under any circumstances.
24
23
 
25
- Our C code follows K&R indentation style (hard tabs, tabs are always 8
24
+ Our C code follows Linux kernel coding style (hard tabs, tabs are always 8
26
25
  characters wide) and NOT the indentation style of Matz Ruby.
27
26
 
28
27
  == Contributing
@@ -51,7 +50,7 @@ don't email the git mailing list or maintainer with kgio patches :)
51
50
 
52
51
  It is easy to install the contents of your git working directory:
53
52
 
54
- Via RubyGems (RubyGems 1.3.5+ recommended for prerelease versions):
53
+ Via RubyGems:
55
54
 
56
55
  gmake install-gem
57
56
 
@@ -64,10 +63,9 @@ installation done without RubyGems, however.
64
63
 
65
64
  === Tests
66
65
 
67
- We use GNU make to run tests in parallel. test/unit/parallel didn't
68
- exist for old versions of Ruby before 1.9.3. Users of GNU-based systems
69
- (such as GNU/Linux) usually have GNU make installed as "make" instead of
70
- "gmake".
66
+ We use GNU make to run tests in parallel for historical reasons. Users
67
+ of GNU-based systems (such as GNU/Linux) usually have GNU make installed
68
+ as "make" instead of "gmake".
71
69
 
72
70
  Running the entire test suite with 4 tests in parallel:
73
71
 
data/README CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  kgio provides non-blocking I/O methods for Ruby without raising
4
4
  exceptions on EAGAIN and EINPROGRESS. It is intended for use with the
5
- Unicorn and Rainbows! Rack servers, but may be used by other
6
- applications (that run on Unix-like platforms).
5
+ unicorn Rack server, but may be used by other applications (that run on
6
+ Unix-like platforms).
7
7
 
8
8
  == Features
9
9
 
10
10
  * Can avoid expensive exceptions on common EAGAIN/EINPROGRESS errors,
11
11
  returning :wait_readable or :wait_writable instead.
12
12
  These exceptions got more expensive to hit under Ruby 1.9.2
13
- (but were fixed in Ruby 1.9.3 and later to 1.9.1 performance levels)
13
+ (but were fixed in Ruby 1.9.3 and later to 1.9.1 performance levels,
14
+ which were still bad)
14
15
 
15
16
  * Returns the unwritten portion of the string on partial writes,
16
17
  making it ideal for buffering unwritten data.
data/TODO CHANGED
@@ -1,2 +1,3 @@
1
1
  * remove old autopush interface (for kgio 3.x)
2
2
  * obsolete kgio by improving *_nonblock methods in Ruby itself
3
+ (Mostly done Ruby 2.3.0)
@@ -160,12 +160,6 @@ 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
-
169
163
  static VALUE
170
164
  my_accept(struct accept_args *a, int force_nonblock)
171
165
  {
@@ -211,7 +205,6 @@ retry:
211
205
  }
212
206
  }
213
207
  client_io = sock_for_fd(a->accepted_class, client_fd);
214
- post_accept(a->accept_io, client_io);
215
208
 
216
209
  if (a->addr)
217
210
  in_addr_set(client_io,
@@ -51,6 +51,7 @@ have_func('rb_thread_call_without_gvl', %w{ruby/thread.h})
51
51
  have_func('rb_thread_blocking_region')
52
52
  have_func('rb_thread_io_blocking_region')
53
53
  have_func('rb_str_set_len')
54
+ have_func("rb_hash_clear", "ruby.h") # Ruby 2.0+
54
55
  have_func('rb_time_interval')
55
56
  have_func('rb_wait_for_single_fd')
56
57
  have_func('rb_str_subseq')
@@ -29,14 +29,9 @@ 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);
33
32
  void init_kgio_poll(void);
34
33
  void init_kgio_tryopen(void);
35
34
 
36
- void kgio_autopush_accept(VALUE, VALUE);
37
- void kgio_autopush_recv(VALUE);
38
- void kgio_autopush_send(VALUE);
39
-
40
35
  VALUE kgio_call_wait_writable(VALUE io);
41
36
  VALUE kgio_call_wait_readable(VALUE io);
42
37
  #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && defined(HAVE_RUBY_THREAD_H)
@@ -90,13 +85,6 @@ NORETURN(void kgio_rd_sys_fail(const char *));
90
85
  # define USE_MSG_DONTWAIT
91
86
  # endif
92
87
 
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
-
100
88
  /* prefer rb_str_subseq because we don't use negative offsets */
101
89
  #ifndef HAVE_RB_STR_SUBSEQ
102
90
  #define MY_STR_SUBSEQ(str,beg,len) rb_str_substr((str),(beg),(len))
@@ -95,7 +95,6 @@ void Init_kgio_ext(void)
95
95
  init_kgio_writev();
96
96
  init_kgio_connect();
97
97
  init_kgio_accept();
98
- init_kgio_autopush();
99
98
  init_kgio_poll();
100
99
  init_kgio_tryopen();
101
100
  }
@@ -12,8 +12,18 @@
12
12
  #endif
13
13
 
14
14
  static VALUE sym_wait_readable, sym_wait_writable;
15
+
16
+ #ifdef HAVE_RB_HASH_CLEAR /* Ruby >= 2.0 */
17
+ # define my_hash_clear(h) (void)rb_hash_clear(h)
18
+ #else /* !HAVE_RB_HASH_CLEAR - Ruby <= 1.9.3 */
15
19
  static ID id_clear;
16
20
 
21
+ static void my_hash_clear(VALUE h)
22
+ {
23
+ rb_funcall(h, id_clear, 0);
24
+ }
25
+ #endif /* HAVE_RB_HASH_CLEAR */
26
+
17
27
  struct poll_args {
18
28
  struct pollfd *fds;
19
29
  nfds_t nfds;
@@ -126,7 +136,7 @@ static VALUE poll_result(int nr, struct poll_args *a)
126
136
  int rc;
127
137
 
128
138
  if ((nfds_t)nr != a->nfds)
129
- rb_funcall(a->ios, id_clear, 0);
139
+ my_hash_clear(a->ios);
130
140
  for (; nr > 0; fds++) {
131
141
  if (fds->revents == 0)
132
142
  continue;
@@ -218,7 +228,9 @@ void init_kgio_poll(void)
218
228
 
219
229
  sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
220
230
  sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
231
+ #ifndef HAVE_RB_HASH_CLEAR
221
232
  id_clear = rb_intern("clear");
233
+ #endif
222
234
 
223
235
  #define c(x) rb_define_const(mKgio,#x,INT2NUM((int)x))
224
236
 
@@ -7,13 +7,8 @@ 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
-
14
10
  #else
15
11
  static const int peek_flags = MSG_PEEK;
16
- static inline void kgio_autopush_read(VALUE io) { kgio_autopush_recv(io); }
17
12
  #endif
18
13
 
19
14
  struct rd_args {
@@ -85,7 +80,6 @@ static VALUE my_read(int io_wait, int argc, VALUE *argv, VALUE io)
85
80
  long n;
86
81
 
87
82
  prepare_read(&a, argc, argv, io);
88
- kgio_autopush_read(io);
89
83
 
90
84
  if (a.len > 0) {
91
85
  set_nonblocking(a.fd);
@@ -158,7 +152,6 @@ static VALUE my_recv(int io_wait, int argc, VALUE *argv, VALUE io)
158
152
  long n;
159
153
 
160
154
  prepare_read(&a, argc, argv, io);
161
- kgio_autopush_recv(io);
162
155
 
163
156
  if (a.len > 0) {
164
157
  retry:
@@ -212,7 +205,6 @@ static VALUE my_peek(int io_wait, int argc, VALUE *argv, VALUE io)
212
205
  long n;
213
206
 
214
207
  prepare_read(&a, argc, argv, io);
215
- kgio_autopush_recv(io);
216
208
 
217
209
  if (a.len > 0) {
218
210
  if (peek_flags == MSG_PEEK)
@@ -72,8 +72,6 @@ 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);
77
75
  return a.buf;
78
76
  }
79
77
 
@@ -126,8 +124,6 @@ retry:
126
124
  n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
127
125
  if (write_check(&a, n, "send", io_wait) != 0)
128
126
  goto retry;
129
- if (TYPE(a.buf) != T_SYMBOL)
130
- kgio_autopush_send(io);
131
127
  return a.buf;
132
128
  }
133
129
 
@@ -90,8 +90,7 @@ static ssize_t custom_writev(int fd, const struct iovec *vec, int iov_cnt, size_
90
90
 
91
91
  result = write(fd, buf, total_len);
92
92
 
93
- /* well, it seems that `free` could not change errno
94
- * but lets save it anyway */
93
+ /* free() may alter errno */
95
94
  i = errno;
96
95
  free(buf);
97
96
  errno = i;
@@ -250,8 +249,6 @@ static VALUE my_writev(VALUE io, VALUE ary, int io_wait)
250
249
  } while (writev_check(&a, n, "writev", io_wait) != 0);
251
250
  rb_str_resize(a.vec_buf, 0);
252
251
 
253
- if (TYPE(a.buf) != T_SYMBOL)
254
- kgio_autopush_write(io);
255
252
  return a.buf;
256
253
  }
257
254
 
@@ -16,6 +16,16 @@ 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
19
29
  end
20
30
 
21
31
  require 'kgio_ext'
@@ -1,165 +1,11 @@
1
- require 'tempfile'
2
1
  require 'test/unit'
3
- begin
4
- $-w = false
5
- RUBY_PLATFORM =~ /linux/ and require 'strace'
6
- rescue LoadError
7
- end
8
- $-w = true
9
2
  require 'kgio'
10
3
 
11
4
  class TestAutopush < Test::Unit::TestCase
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
5
+ def test_compatibility
102
6
  Kgio.autopush = true
103
7
  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
163
8
  Kgio.autopush = false
9
+ assert_equal false, Kgio.autopush?
164
10
  end
165
- end if RUBY_PLATFORM =~ /linux|freebsd/
11
+ end
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.9.3
4
+ version: 2.10.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-01-12 00:00:00.000000000 Z
11
+ date: 2015-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: olddoc
@@ -41,8 +41,8 @@ dependencies:
41
41
  description: |-
42
42
  kgio provides non-blocking I/O methods for Ruby without raising
43
43
  exceptions on EAGAIN and EINPROGRESS. It is intended for use with the
44
- Unicorn and Rainbows! Rack servers, but may be used by other
45
- applications (that run on Unix-like platforms).
44
+ unicorn Rack server, but may be used by other applications (that run on
45
+ Unix-like platforms).
46
46
  email: kgio-public@bogomips.org
47
47
  executables: []
48
48
  extensions:
@@ -57,7 +57,6 @@ extra_rdoc_files:
57
57
  - HACKING
58
58
  - lib/kgio.rb
59
59
  - ext/kgio/accept.c
60
- - ext/kgio/autopush.c
61
60
  - ext/kgio/connect.c
62
61
  - ext/kgio/kgio_ext.c
63
62
  - ext/kgio/poll.c
@@ -83,7 +82,6 @@ files:
83
82
  - archive/slrnpull.conf
84
83
  - ext/kgio/accept.c
85
84
  - ext/kgio/ancient_ruby.h
86
- - ext/kgio/autopush.c
87
85
  - ext/kgio/blocking_io_region.h
88
86
  - ext/kgio/broken_system_compat.h
89
87
  - ext/kgio/connect.c
@@ -154,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
152
  version: '0'
155
153
  requirements: []
156
154
  rubyforge_project:
157
- rubygems_version: 2.4.5
155
+ rubygems_version: 2.5.0
158
156
  signing_key:
159
157
  specification_version: 4
160
158
  summary: kinder, gentler I/O for Ruby
@@ -1,247 +0,0 @@
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
- static VALUE s_set_autopush(VALUE self, VALUE val)
109
- {
110
- enabled = RTEST(val);
111
-
112
- return val;
113
- }
114
-
115
- /*
116
- * call-seq:
117
- *
118
- * io.kgio_autopush? -> true or false
119
- *
120
- * Returns the current autopush state of the Kgio::SocketMethods-enabled
121
- * socket.
122
- *
123
- * Only available on systems with TCP_CORK (Linux) or
124
- * TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
125
- */
126
- static VALUE autopush_get(VALUE io)
127
- {
128
- return state_get(io) <= 0 ? Qfalse : Qtrue;
129
- }
130
-
131
- /*
132
- * call-seq:
133
- *
134
- * io.kgio_autopush = true
135
- * io.kgio_autopush = false
136
- *
137
- * Enables or disables autopush on any given Kgio::SocketMethods-capable
138
- * IO object. This does NOT enable or disable TCP_NOPUSH/TCP_CORK right
139
- * away, that must be done with IO.setsockopt
140
- *
141
- * Only available on systems with TCP_CORK (Linux) or
142
- * TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
143
- */
144
- static VALUE autopush_set(VALUE io, VALUE vbool)
145
- {
146
- if (RTEST(vbool))
147
- state_set(io, AUTOPUSH_STATE_WRITER);
148
- else
149
- state_set(io, AUTOPUSH_STATE_IGNORE);
150
- return vbool;
151
- }
152
-
153
- void init_kgio_autopush(void)
154
- {
155
- VALUE mKgio = rb_define_module("Kgio");
156
- VALUE tmp;
157
-
158
- rb_define_singleton_method(mKgio, "autopush?", s_get_autopush, 0);
159
- rb_define_singleton_method(mKgio, "autopush=", s_set_autopush, 1);
160
-
161
- tmp = rb_define_module_under(mKgio, "SocketMethods");
162
- rb_define_method(tmp, "kgio_autopush=", autopush_set, 1);
163
- rb_define_method(tmp, "kgio_autopush?", autopush_get, 0);
164
-
165
- id_autopush_state = rb_intern("@kgio_autopush_state");
166
- }
167
-
168
- /*
169
- * called after a successful write, just mark that we've put something
170
- * in the skb and will need to uncork on the next write.
171
- */
172
- void kgio_autopush_send(VALUE io)
173
- {
174
- if (state_get(io) == AUTOPUSH_STATE_WRITER)
175
- state_set(io, AUTOPUSH_STATE_WRITTEN);
176
- }
177
-
178
- /* called on successful accept() */
179
- void kgio_autopush_accept(VALUE accept_io, VALUE client_io)
180
- {
181
- enum autopush_state acceptor_state;
182
-
183
- if (!enabled)
184
- return;
185
- acceptor_state = state_get(accept_io);
186
- if (acceptor_state == AUTOPUSH_STATE_IGNORE)
187
- acceptor_state = detect_acceptor_state(accept_io);
188
- if (acceptor_state == AUTOPUSH_STATE_ACCEPTOR)
189
- state_set(client_io, AUTOPUSH_STATE_WRITER);
190
- else
191
- state_set(client_io, AUTOPUSH_STATE_IGNORE);
192
- }
193
-
194
- void kgio_autopush_recv(VALUE io)
195
- {
196
- if (enabled && (state_get(io) == AUTOPUSH_STATE_WRITTEN)) {
197
- push_pending_data(io);
198
- state_set(io, AUTOPUSH_STATE_WRITER);
199
- }
200
- }
201
-
202
- static enum autopush_state detect_acceptor_state(VALUE io)
203
- {
204
- int corked = 0;
205
- int fd = my_fileno(io);
206
- socklen_t optlen = sizeof(int);
207
- enum autopush_state state;
208
-
209
- if (getsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &corked, &optlen) != 0) {
210
- if (errno != EOPNOTSUPP)
211
- rb_sys_fail("getsockopt(TCP_CORK/TCP_NOPUSH)");
212
- errno = 0;
213
- state = AUTOPUSH_STATE_ACCEPTOR_IGNORE;
214
- } else if (corked) {
215
- state = AUTOPUSH_STATE_ACCEPTOR;
216
- } else {
217
- state = AUTOPUSH_STATE_ACCEPTOR_IGNORE;
218
- }
219
- state_set(io, state);
220
-
221
- return state;
222
- }
223
-
224
- /*
225
- * checks to see if we've written anything since the last recv()
226
- * If we have, uncork the socket and immediately recork it.
227
- */
228
- static void push_pending_data(VALUE io)
229
- {
230
- int optval = 0;
231
- const socklen_t optlen = sizeof(int);
232
- const int fd = my_fileno(io);
233
-
234
- if (setsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &optval, optlen) != 0)
235
- rb_sys_fail("setsockopt(TCP_CORK/TCP_NOPUSH, 0)");
236
- /* immediately recork */
237
- optval = 1;
238
- if (setsockopt(fd, IPPROTO_TCP, KGIO_NOPUSH, &optval, optlen) != 0)
239
- rb_sys_fail("setsockopt(TCP_CORK/TCP_NOPUSH, 1)");
240
- }
241
- #else /* !KGIO_NOPUSH */
242
- void kgio_autopush_recv(VALUE io){}
243
- void kgio_autopush_send(VALUE io){}
244
- void init_kgio_autopush(void)
245
- {
246
- }
247
- #endif /* ! KGIO_NOPUSH */