From d3cf61b05d9507e7b6ea5a1a1192e107a8612049 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 13 Dec 2015 12:19:00 +0000 Subject: switch to exception-free non-blocking I/O Ruby 2.3 will have `exception: false' support in socket-related classes. Additionally, 2.3 will implement the existing IO#*_nonblock methods more efficiently than before by avoiding the hash allocation necessary for keywords. For users on older Rubies, we'll continue supporting them with compatibility wrappers; even Ruby 1.9.3 users (for now). --- lib/dtas/unix_accepted.rb | 77 +++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 30 deletions(-) (limited to 'lib/dtas/unix_accepted.rb') diff --git a/lib/dtas/unix_accepted.rb b/lib/dtas/unix_accepted.rb index a0000cf..7db3ed5 100644 --- a/lib/dtas/unix_accepted.rb +++ b/lib/dtas/unix_accepted.rb @@ -17,55 +17,48 @@ class DTAS::UNIXAccepted # :nodoc: def emit(msg) buffered = @send_buf.size if buffered == 0 - begin - @to_io.sendmsg_nonblock(msg, Socket::MSG_EOR) - return :wait_readable - rescue Errno::EAGAIN - @send_buf << msg - return :wait_writable - rescue => e - return e + case rv = sendmsg_nonblock(msg) + when :wait_writable then @send_buf << msg end + rv elsif buffered > 100 - return RuntimeError.new("too many messages buffered") + RuntimeError.new("too many messages buffered") else # buffered > 0 @send_buf << msg - return :wait_writable + :wait_writable end + rescue => e + e end # flushes pending data if it got buffered def writable_iter - begin - msg = @send_buf.shift or return :wait_readable - @to_io.send_nonblock(msg, Socket::MSG_EOR) - rescue Errno::EAGAIN - @send_buf.unshift(msg) - return :wait_writable - rescue => e - return e - end while true + case sendmsg_nonblock(@send_buf[0]) + when :wait_writable then return :wait_writable + else + @send_buf.shift + end until @send_buf.empty? + :wait_readable + rescue => e + e end def readable_iter - io = @to_io - nread = io.nread + nread = @to_io.nread # EOF, assume no spurious wakeups for SOCK_SEQPACKET return nil if nread == 0 - begin - begin - msg = io.recv_nonblock(nread) - rescue Errno::EAGAIN - return :wait_readable - rescue EOFError, SystemCallError - return nil - end + case msg = recv_nonblock(nread) + when :wait_readable then return msg + when '', nil then return nil # EOF + else yield(self, msg) # DTAS::Player deals with this - nread = io.nread + nread = @to_io.nread end while nread > 0 :wait_readable + rescue SystemCallError + nil end def close @@ -75,4 +68,28 @@ class DTAS::UNIXAccepted # :nodoc: def closed? @to_io.closed? end + + if RUBY_VERSION.to_f >= 2.3 + def sendmsg_nonblock(msg) + @to_io.sendmsg_nonblock(msg, Socket::MSG_EOR, exception: false) + end + + def recv_nonblock(len) + @to_io.recv_nonblock(len, exception: false) + end + else + def sendmsg_nonblock(msg) + @to_io.sendmsg_nonblock(msg, Socket::MSG_EOR) + rescue IO::WaitWritable + :wait_writable + end + + def recv_nonblock(len) + @to_io.recv_nonblock(len) + rescue IO::WaitReadable + :wait_readable + rescue EOFError + nil + end + end end -- cgit v1.2.3-24-ge0c7