Skip to content

Commit

Permalink
Handle long reads and use IO#readpartial
Browse files Browse the repository at this point in the history
The complete read might not show up in the first read() call,
so continue looping until the target length is reached.

Use IO#readpartial instead of looping with IO#sysread; the difference is
that readpartial loops on EAGAIN and EINTR, but it uses select() to wait
for a readable handle instead of doing a busy retry.
  • Loading branch information
sodabrew committed Oct 9, 2015
1 parent 9fc84d1 commit 93b9833
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 8 deletions.
15 changes: 8 additions & 7 deletions code/protocol.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,15 @@ def do_write(client, buff)
defined?(nwritten) ? nwritten : 0
end

def do_read(client, numr = 32768)
client.sysread(numr)
rescue Errno::EAGAIN, Errno::EINTR # Ruby threading can cause an alarm/timer interrupt on a syscall
sleep 0.001 # A tiny pause to prevent consuming all CPU
retry
def do_read(client, size)
out = ""
while out.bytesize < size
remain = size - out.bytesize
out << client.readpartial(remain)
end
out
rescue EOFError
$log.debug("Got an EOF from socket read")
return nil
out
rescue Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
raise "Got an #{$!} from socket read"
end
Expand Down
2 changes: 1 addition & 1 deletion code/queue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ def handle_status_read(msg)
child_pid = msg['child_pid']

$log.debug("#{child_pid}: Reading status from child")
data = do_read(child_io, 4096)
data = child_io.readpartial(4096) rescue nil
return false unless data

child_msgs = data.split("\n")
Expand Down

0 comments on commit 93b9833

Please sign in to comment.