Skip to content

Commit

Permalink
Merge pull request #3541 from rubinius/wait-readable-writable
Browse files Browse the repository at this point in the history
Update raising of WaitReadable/WaitWritable exceptions
  • Loading branch information
brixen committed Dec 25, 2015
2 parents fde04fc + 6216f2d commit efc8770
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 14 deletions.
16 changes: 16 additions & 0 deletions kernel/common/io.rb
Expand Up @@ -14,6 +14,22 @@ class EAGAINWaitWritable < Errno::EAGAIN
include ::IO::WaitWritable
end

class EWOULDBLOCKWaitReadable < Errno::EAGAIN
include WaitReadable
end

class EWOULDBLOCKWaitWritable < Errno::EAGAIN
include WaitWritable
end

class EINPROGRESSWaitReadable < Errno::EINPROGRESS
include WaitReadable
end

class EINPROGRESSWaitWritable < Errno::EINPROGRESS
include WaitWritable
end

# Import platform constants

SEEK_SET = Rubinius::Config['rbx.platform.io.SEEK_SET']
Expand Down
8 changes: 2 additions & 6 deletions spec/ruby/core/io/read_nonblock_spec.rb
Expand Up @@ -11,12 +11,8 @@
@write.close rescue nil
end

it "raises EAGAIN when there is no data" do
lambda { @read.read_nonblock(5) }.should raise_error(Errno::EAGAIN)
end

it "raises IO::WaitReadable when there is no data" do
lambda { @read.read_nonblock(5) }.should raise_error(IO::WaitReadable)
it "raises IO::EAGAINWaitReadable when there is no data" do
lambda { @read.read_nonblock(5) }.should raise_error(IO::EAGAINWaitReadable)
end

it "returns at most the number of bytes requested" do
Expand Down
16 changes: 16 additions & 0 deletions spec/ruby/core/io/write_nonblock_spec.rb
Expand Up @@ -34,6 +34,22 @@
end
end

describe 'IO#write_nonblock' do
before do
@read, @write = IO.pipe
end

after do
@read.close
@write.close
end

it 'raises IO::EAGAINWaitWritable when the operation would block' do
proc { loop { @write.write_nonblock('a' * 10_000) } }
.should raise_error(IO::EAGAINWaitWritable)
end
end

describe "IO#write_nonblock" do
it_behaves_like :io_write, :write_nonblock
end
41 changes: 36 additions & 5 deletions vm/builtin/exception.cpp
Expand Up @@ -313,15 +313,46 @@ namespace rubinius {
RubyException::raise(exc);
}

void Exception::errno_eagain_error(STATE, const char* reason) {
void Exception::errno_wait_readable(STATE, int error) {
Exception* exc;
Class* exc_class = as<Class>(G(io)->get_const(state, "EAGAINWaitReadable"));
Class* exc_class;

String* message = nil<String>();
if(error == EAGAIN) {
exc_class = as<Class>(G(io)->get_const(state, "EAGAINWaitReadable"));
}
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
else if(error == EWOULDBLOCK) {
exc_class = as<Class>(G(io)->get_const(state, "EWOULDBLOCKWaitReadable"));
}
#endif
else {
exc_class = get_errno_error(state, Fixnum::from(error));
}

if(reason) {
message = String::create(state, reason);
String* message = String::create(state, "read would block");

exc = make_errno_exception(state, exc_class, message, cNil);

RubyException::raise(exc);
}

void Exception::errno_wait_writable(STATE, int error) {
Exception* exc;
Class* exc_class;

if(error == EAGAIN) {
exc_class = as<Class>(G(io)->get_const(state, "EAGAINWaitWritable"));
}
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
else if(error == EWOULDBLOCK) {
exc_class = as<Class>(G(io)->get_const(state, "EWOULDBLOCKWaitWritable"));
}
#endif
else {
exc_class = get_errno_error(state, Fixnum::from(error));
}

String* message = String::create(state, "write would block");

exc = make_errno_exception(state, exc_class, message, cNil);

Expand Down
4 changes: 3 additions & 1 deletion vm/builtin/exception.hpp
Expand Up @@ -88,7 +88,9 @@ namespace rubinius {

static void errno_error(STATE, const char* reason = NULL, int ern = 0,
const char* entity = 0);
static void errno_eagain_error(STATE, const char* reason);

static void errno_wait_readable(STATE, int error);
static void errno_wait_writable(STATE, int error);

/**
* Convenience predicates for checking the class of an
Expand Down
4 changes: 2 additions & 2 deletions vm/builtin/io.cpp
Expand Up @@ -727,7 +727,7 @@ namespace rubinius {
int res = ::select(fd+1, &set, 0, 0, &tv);

if(res == 0) {
Exception::errno_eagain_error(state, "no data ready");
Exception::errno_wait_readable(state, EAGAIN);
return 0;
} else if(res <= 0) {
Exception::errno_error(state, "read(2) failed");
Expand Down Expand Up @@ -834,7 +834,7 @@ namespace rubinius {

// We can use byte_address() here since we use an explicit size
int n = ::write(descriptor_->to_native(), buf->byte_address(), buf_size);
if(n == -1) Exception::errno_error(state, "write_nonblock");
if(n == -1) Exception::errno_wait_writable(state, errno);

state->vm()->metrics().system.write_bytes += n;

Expand Down

0 comments on commit efc8770

Please sign in to comment.