diff options
author | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-04-19 01:08:16 +0000 |
---|---|---|
committer | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-04-19 01:08:16 +0000 |
commit | c32fc82d0ed8bcf0d6e4de8518bbb7bd808a69b8 (patch) | |
tree | a92b3b9275d623968562e7e984375e80a67ff8b8 /test/socket | |
parent | 0013fdaaa5145f2003d96b6e54a5f16f16f3678b (diff) |
socket: avoid fcntl for read/write_nonblock on Linux
On platforms where MSG_DONTWAIT works reliably on all sockets
(so far, I know of Linux), we can avoid fcntl syscalls and
implement IO#write_nonblock and IO#read_nonblock in terms of the
socket-specific send and recv family of syscalls.
This avoids side effects on the socket, and also encourages
generic code to be written in cases where IO wrappers like
OpenSSL::SSL::SSLSocket are used.
Perhaps in the future, side-effect-free non-blocking I/O can
be standard on all files and OSes: https://cr.yp.to/unix/nonblock.html
* ext/socket/lib/socket.rb (read_nonblock, write_nonblock):
Linux-specific wrapper without side effects
[ruby-core:80780] [Feature #13362]
* test/socket/test_basicsocket.rb (test_read_write_nonblock):
new test
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58400 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'test/socket')
-rw-r--r-- | test/socket/test_basicsocket.rb | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/test/socket/test_basicsocket.rb b/test/socket/test_basicsocket.rb index e17a675d8a..0b13a7f1af 100644 --- a/test/socket/test_basicsocket.rb +++ b/test/socket/test_basicsocket.rb @@ -3,6 +3,7 @@ begin require "socket" require "test/unit" + require "io/nonblock" rescue LoadError end @@ -152,4 +153,53 @@ class TestSocket_BasicSocket < Test::Unit::TestCase sock.close end end + + def test_read_write_nonblock + socks do |sserv, ssock, csock| + set_nb = true + buf = String.new + if ssock.respond_to?(:nonblock?) + assert_not_predicate(ssock, :nonblock?) + assert_not_predicate(csock, :nonblock?) + + # Linux may use MSG_DONTWAIT to avoid setting O_NONBLOCK + if RUBY_PLATFORM.match?(/linux/) && Socket.const_defined?(:MSG_DONTWAIT) + set_nb = false + end + end + assert_equal :wait_readable, ssock.read_nonblock(1, buf, exception: false) + assert_equal 5, csock.write_nonblock('hello') + IO.select([ssock]) + assert_same buf, ssock.read_nonblock(5, buf, exception: false) + assert_equal 'hello', buf + buf = '*' * 16384 + n = 0 + + case w = csock.write_nonblock(buf, exception: false) + when Integer + n += w + when :wait_writable + break + end while true + + assert_equal :wait_writable, w + assert_raise(IO::WaitWritable) { loop { csock.write_nonblock(buf) } } + assert_operator n, :>, 0 + assert_not_predicate(csock, :nonblock?, '[Feature #13362]') unless set_nb + csock.close + + case r = ssock.read_nonblock(16384, buf, exception: false) + when String + next + when nil + break + else + flunk "unexpected read_nonblock return: #{r.inspect}" + end while true + + assert_raise(EOFError) { ssock.read_nonblock(1) } + + assert_not_predicate(ssock, :nonblock?) unless set_nb + end + end end if defined?(BasicSocket) |