Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rubinius/rubinius
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 51c5faca3054
Choose a base ref
...
head repository: rubinius/rubinius
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 23ade6568fbb
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Jan 19, 2016

  1. Copy the full SHA
    b4a4789 View commit details

Commits on Jan 20, 2016

  1. emulate blocking read behavior using #read_nonblock

    We had a failing spec where a thread blocked on read was
    supposed to raise IOError when *another thread* closed
    the IO. However, it didn't work. Turns out that the
    low-level system read function blocks forever so the
    closed IO/file descriptor didn't raise as expected.
    
    The original C code got around this OS behavior by setting
    special flags and sending signals to the blocked thread
    to wake it up. This mechanism was only exposed to the
    bytecode VM and wasn't available to the Ruby runtime so
    I had to go this other direction. It's less than ideal
    but if the long-term plan is to utilize libuv for
    Rubinius IO then this is a good enough fix.
    chuckremes committed Jan 20, 2016
    Copy the full SHA
    23ade65 View commit details
Showing with 30 additions and 78 deletions.
  1. +30 −3 kernel/common/io.rb
  2. +0 −75 spec/ruby/core/io/y_spec.rb
33 changes: 30 additions & 3 deletions kernel/common/io.rb
Original file line number Diff line number Diff line change
@@ -729,7 +729,7 @@ def sysseek(offset, whence=SEEK_SET)
end
end # class FIFOFileDescriptor

class DirectoryFileDescriptor < FileDescriptor
class DirectoryFileDescriptor < BufferedFileDescriptor
end # class DirectoryFileDescriptor

class SocketFileDescriptor < FIFOFileDescriptor
@@ -2635,7 +2635,9 @@ def read(length=nil, buffer=nil)
end

str = ""
result = @fd.read(length, str)
emulate_blocking_read do
read_nonblock(length, str)
end

if str.empty? && length > 0
str = nil
@@ -2660,7 +2662,9 @@ def read_all
str = ""
begin
buffer = ""
@fd.read(nil, buffer)
emulate_blocking_read do
read_nonblock(FileDescriptor.pagesize, buffer)
end
str << buffer
end until eof?

@@ -2722,12 +2726,19 @@ def read_nonblock(size, buffer=nil)

buffer = StringValue buffer if buffer

unless @fd.blocking?
@fd.set_nonblock
nonblock_reset = true
end

if str = read_if_available(size)
buffer.replace(str) if buffer
return str
else
raise EOFError, "stream closed"
end
ensure
@fd.clear_nonblock if nonblock_reset
end

##
@@ -3328,6 +3339,22 @@ def invalid_descriptor?
descriptor == -1 || descriptor.nil?
end
private :invalid_descriptor?

def emulate_blocking_read
# Simple wrapper intended to wrap a call to #read_nonblock.
# Loops forever while waiting for data to become available
# just like a blocking read, but avoids blocking on the
# low-level read(2) call. Allows us to catch situations
# where another thread has closed the FD.
begin
yield
rescue IO::EAGAINWaitReadable
sleep 0.10
retry
rescue EOFError
end
end
private :emulate_blocking_read
end

##
75 changes: 0 additions & 75 deletions spec/ruby/core/io/y_spec.rb

This file was deleted.