kgio 2.9.3 → 2.10.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: 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 */