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 /ext/socket/lib | |
parent | 0013fdaaa5145f2003d96b6e54a5f16f16f3678b (diff) | |
download | ruby-c32fc82d0ed8bcf0d6e4de8518bbb7bd808a69b8.tar.gz |
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 'ext/socket/lib')
-rw-r--r-- | ext/socket/lib/socket.rb | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb index de5eda3991..8127009fff 100644 --- a/ext/socket/lib/socket.rb +++ b/ext/socket/lib/socket.rb @@ -442,6 +442,24 @@ class BasicSocket < IO scm_rights: false, exception: true) __recvmsg_nonblock(dlen, flags, clen, scm_rights, exception) end + + # Linux-specific optimizations to avoid fcntl for IO#read_nonblock + # and IO#write_nonblock using MSG_DONTWAIT + # Do other platforms suport MSG_DONTWAIT reliably? + if RUBY_PLATFORM =~ /linux/ && Socket.const_defined?(:MSG_DONTWAIT) + def read_nonblock(len, str = nil, exception: true) # :nodoc: + case rv = __recv_nonblock(len, 0, str, exception) + when '' # recv_nonblock returns empty string on EOF + exception ? raise(EOFError, 'end of file reached') : nil + else + rv + end + end + + def write_nonblock(buf, exception: true) # :nodoc: + __sendmsg_nonblock(buf, 0, nil, nil, exception) + end + end end class Socket < BasicSocket |