Project

General

Profile

Feature #5138 » nonblock_tuple.patch

nonblock with a tuple - tenderlovemaking (Aaron Patterson), 07/10/2013 06:24 AM

View differences:

ext/openssl/lib/openssl/buffering.rb
ret
end
def try_read_nonblock(maxlen, buf=nil)
if maxlen == 0
if buf
buf.clear
return [buf, nil]
else
return ["", nil]
end
end
if @rbuffer.empty?
return try_sysread_nonblock(maxlen, buf)
end
ret = consume_rbuff(maxlen)
if buf
buf.replace(ret)
ret = buf
end
raise EOFError if ret.empty?
[ret, nil]
end
##
# Reads the next "line+ from the stream. Lines are separated by +eol+. If
# +limit+ is provided the result will not be longer than the given number of
......
syswrite_nonblock(s)
end
def try_write_nonblock(s)
flush
try_syswrite_nonblock(s)
end
##
# Writes +s+ to the stream. +s+ will be converted to a String using
# String#to_s.
ext/openssl/ossl_ssl.c
}
static VALUE
ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock, int no_exception)
{
SSL *ssl;
int ilen, nread = 0;
......
rb_str_modify(str);
rb_str_resize(str, ilen);
}
if(ilen == 0) return str;
if(ilen == 0) {
if (no_exception) {
return rb_ary_new_from_args(2, str, Qnil);
} else {
return str;
}
}
Data_Get_Struct(self, SSL, ssl);
GetOpenFile(ossl_ssl_get_io(self), fptr);
......
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_ZERO_RETURN:
if (no_exception) { return rb_ary_new_from_args(2, Qnil, Qnil); }
rb_eof_error();
case SSL_ERROR_WANT_WRITE:
if (no_exception) {
return rb_ary_new_from_args(2, Qnil, ID2SYM(rb_intern("wait_writable")));
}
write_would_block(nonblock);
rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
if (no_exception) {
return rb_ary_new_from_args(2, Qnil, ID2SYM(rb_intern("wait_readable")));
}
read_would_block(nonblock);
rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_SYSCALL:
if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
if(ERR_peek_error() == 0 && nread == 0) {
if (no_exception) { return rb_ary_new_from_args(2, Qnil, Qnil); }
rb_eof_error();
}
rb_sys_fail(0);
default:
ossl_raise(eSSLError, "SSL_read");
......
}
}
else {
ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread");
ID meth;
if (nonblock) {
if (no_exception) {
meth = rb_intern("try_read_nonblock");
} else {
meth = rb_intern("read_nonblock");
}
} else {
meth = rb_intern("sysread");
}
rb_warning("SSL session is not started yet.");
return rb_funcall(ossl_ssl_get_io(self), meth, 2, len, str);
}
......
rb_str_set_len(str, nread);
OBJ_TAINT(str);
return str;
if (no_exception) {
return rb_ary_new_from_args(2, str, Qnil);
} else {
return str;
}
}
/*
......
static VALUE
ossl_ssl_read(int argc, VALUE *argv, VALUE self)
{
return ossl_ssl_read_internal(argc, argv, self, 0);
return ossl_ssl_read_internal(argc, argv, self, 0, 0);
}
/*
......
static VALUE
ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self)
{
return ossl_ssl_read_internal(argc, argv, self, 1);
return ossl_ssl_read_internal(argc, argv, self, 1, 0);
}
/*
* call-seq:
* ssl.try_sysread_nonblock(length) => string, :wait_writable,
* :wait_readable, or nil (for EOF)
* ssl.try_sysread_nonblock(length, buffer) => buffer, :wait_writable,
* :wait_readable, or nil (for EOF)
*
* Exactly the same as +sysread_nonblock+, except that instead of raising
* exceptions for EOF or when the read would block, it returns nil,
* :wait_readable or :wait_writable.
*/
static VALUE
ossl_ssl_try_read_nonblock(int argc, VALUE *argv, VALUE self)
{
return ossl_ssl_read_internal(argc, argv, self, 1, 1);
}
static VALUE
ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock)
ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock, int no_exception)
{
SSL *ssl;
int nwrite = 0;
......
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_WANT_WRITE:
if (no_exception) {
return rb_ary_new_from_args(2, Qnil, ID2SYM(rb_intern("wait_writable")));
}
write_would_block(nonblock);
rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
if (no_exception) {
return rb_ary_new_from_args(2, Qnil, ID2SYM(rb_intern("wait_readable")));
}
read_would_block(nonblock);
rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
......
}
end:
return INT2NUM(nwrite);
if (no_exception) {
return rb_ary_new_from_args(2, INT2NUM(nwrite), Qnil);
} else {
return INT2NUM(nwrite);
}
}
/*
......
static VALUE
ossl_ssl_write(VALUE self, VALUE str)
{
return ossl_ssl_write_internal(self, str, 0);
return ossl_ssl_write_internal(self, str, 0, 0);
}
/*
......
static VALUE
ossl_ssl_write_nonblock(VALUE self, VALUE str)
{
return ossl_ssl_write_internal(self, str, 1);
return ossl_ssl_write_internal(self, str, 1, 0);
}
/*
* call-seq:
* ssl.syswrite_nonblock(string) => Integer, :wait_readable or
* :wait_writable
*
* Exactly the same as +syswrite_nonblock+, except that instead of
* raising an exception if the write would block, returns
* :wait_readable or :wait_writable.
*/
static VALUE
ossl_ssl_try_write_nonblock(VALUE self, VALUE str)
{
return ossl_ssl_write_internal(self, str, 1, 1);
}
/*
......
rb_define_method(cSSLSocket, "accept_nonblock", ossl_ssl_accept_nonblock, 0);
rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1);
rb_define_private_method(cSSLSocket, "sysread_nonblock", ossl_ssl_read_nonblock, -1);
rb_define_private_method(cSSLSocket, "try_sysread_nonblock", ossl_ssl_try_read_nonblock, -1);
rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1);
rb_define_private_method(cSSLSocket, "syswrite_nonblock", ossl_ssl_write_nonblock, 1);
rb_define_private_method(cSSLSocket, "try_syswrite_nonblock", ossl_ssl_try_write_nonblock, 1);
rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0);
rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0);
rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0);
ext/stringio/stringio.c
return val;
}
/*
* call-seq:
* strio.try_sysread(integer[, outbuf]) -> string or nil
*
* Exactly the same as +sysread+, except that instead of raising an
* EOFError at EOF, returns nil. This matches the +read_nonblock+
* protocol from the IO class.
*/
static VALUE
strio_try_sysread(int argc, VALUE *argv, VALUE self)
{
if (argc == 0) { rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)", argc); }
VALUE val = strio_read(argc, argv, self);
if (NIL_P(val)) {
return rb_ary_new_from_args(2, Qnil, Qnil);
}
return rb_ary_new_from_args(2, val, Qnil);
}
#define strio_syswrite rb_io_write
#define strio_isatty strio_false
......
rb_define_method(mReadable, "sysread", strio_sysread, -1);
rb_define_method(mReadable, "readpartial", strio_sysread, -1);
rb_define_method(mReadable, "read_nonblock", strio_sysread, -1);
rb_define_method(StringIO, "try_read_nonblock", strio_try_sysread, -1);
rb_include_module(StringIO, mReadable);
}
{
io.c
rb_readwrite_sys_fail(int writable, const char *mesg);
static VALUE
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock, int no_exception)
{
rb_io_t *fptr;
VALUE length, str;
......
if (n < 0) {
if (!nonblock && rb_io_wait_readable(fptr->fd))
goto again;
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "read would block");
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
if (no_exception) {
return ID2SYM(rb_intern("wait_readable"));
} else {
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "read would block");
}
}
rb_sys_fail_path(fptr->pathv);
}
}
......
{
VALUE ret;
ret = io_getpartial(argc, argv, io, 0);
ret = io_getpartial(argc, argv, io, 0, 0);
if (NIL_P(ret))
rb_eof_error();
return ret;
......
{
VALUE ret;
ret = io_getpartial(argc, argv, io, 1);
ret = io_getpartial(argc, argv, io, 1, 0);
if (NIL_P(ret))
rb_eof_error();
return ret;
}
/**
* call-seq:
* ios.try_read_nonblock(maxlen) -> string, nil, or :wait_readable
* ios.try_read_nonblock(maxlen, outbuf) -> outbuf, nil, or :wait_readable
*
* +try_read_nonblock+ is identical to +read_nonblock+,
* except that instead of raising exceptions, blocking
* calls will return :wait_readable, and EOF will
* return nil.
*/
static VALUE
io_try_read_nonblock(int argc, VALUE *argv, VALUE io)
{
VALUE ret;
ret = io_getpartial(argc, argv, io, 1, 1);
if (NIL_P(ret))
return rb_ary_new_from_args(2, Qnil, Qnil);
else
if (SYMBOL_P(ret))
return rb_ary_new_from_args(2, Qnil, ret);
else
return rb_ary_new_from_args(2, ret, Qnil);
}
static VALUE
io_write_nonblock(VALUE io, VALUE str, int no_exception)
{
rb_io_t *fptr;
long n;
if (!RB_TYPE_P(str, T_STRING))
str = rb_obj_as_string(str);
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
if (io_fflush(fptr) < 0)
rb_sys_fail(0);
rb_io_set_nonblock(fptr);
n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
if (n == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
if (no_exception) {
return ID2SYM(rb_intern("wait_writable"));
} else {
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
}
}
rb_sys_fail_path(fptr->pathv);
}
return LONG2FIX(n);
}
/*
* call-seq:
* ios.write_nonblock(string) -> integer
......
static VALUE
rb_io_write_nonblock(VALUE io, VALUE str)
{
rb_io_t *fptr;
long n;
if (!RB_TYPE_P(str, T_STRING))
str = rb_obj_as_string(str);
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
if (io_fflush(fptr) < 0)
rb_sys_fail(0);
return io_write_nonblock(io, str, 0);
}
rb_io_set_nonblock(fptr);
n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
/*
* call-seq:
* ios.try_write_nonblock(string) -> integer or :wait_writable
*
* Works exactly like write_nonblock, with one exception:
*
* * if the write would block, <code>try_write_nonblock</code> returns
* :wait_writable rather than raising IO::WaitWritable
*/
static VALUE
rb_io_try_write_nonblock(VALUE io, VALUE str)
{
VALUE ret;
if (n == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN)
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
rb_sys_fail_path(fptr->pathv);
}
ret = io_write_nonblock(io, str, 1);
return LONG2FIX(n);
if (SYMBOL_P(ret))
return rb_ary_new_from_args(2, Qnil, ret);
else
return rb_ary_new_from_args(2, ret, Qnil);
}
/*
......
RUBY_METHOD_FUNC(0), Qnil, rb_eEOFError, (VALUE)0);
}
else {
tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock);
tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock, 0);
}
if (NIL_P(tmp)) {
if (ARGF.next_p == -1) {
......
rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
rb_define_method(rb_cIO, "read_nonblock", io_read_nonblock, -1);
rb_define_method(rb_cIO, "try_read_nonblock", io_try_read_nonblock, -1);
rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, 1);
rb_define_method(rb_cIO, "try_write_nonblock", rb_io_try_write_nonblock, 1);
rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
rb_define_method(rb_cIO, "read", io_read, -1);
rb_define_method(rb_cIO, "write", io_write_m, 1);
test/openssl/test_pair.rb
ret = nil
assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10) }
assert_equal("def\n", ret)
s1.close
assert_raise(EOFError) { s2.read_nonblock(10) }
}
end
def test_try_read_nonblock
ssl_pair {|s1, s2|
assert_equal [nil, :wait_readable], s2.try_read_nonblock(10)
s1.write "abc\ndef\n"
IO.select([s2])
assert_equal("ab", s2.try_read_nonblock(2).first)
assert_equal("c\n", s2.gets)
ret = nil
assert_nothing_raised("[ruby-core:20298]") { ret, = s2.try_read_nonblock(10) }
assert_equal("def\n", ret)
s1.close
assert_equal(nil, s2.try_read_nonblock(10).first)
}
end
def write_nonblock(socket, meth, str)
ret, = socket.send(meth, str)
ret || 0
end
def test_write_nonblock
ssl_pair {|s1, s2|
n = 0
begin
n += s1.write_nonblock("a" * 100000)
n += s1.write_nonblock("b" * 100000)
n += s1.write_nonblock("c" * 100000)
n += s1.write_nonblock("d" * 100000)
n += s1.write_nonblock("e" * 100000)
n += s1.write_nonblock("f" * 100000)
n += write_nonblock s1, :write_nonblock, "a" * 100000
n += write_nonblock s1, :write_nonblock, "b" * 100000
n += write_nonblock s1, :write_nonblock, "c" * 100000
n += write_nonblock s1, :write_nonblock, "d" * 100000
n += write_nonblock s1, :write_nonblock, "e" * 100000
n += write_nonblock s1, :write_nonblock, "f" * 100000
rescue IO::WaitWritable
end
s1.close
......
}
end
def test_try_write_nonblock
ssl_pair {|s1, s2|
n = 0
n += write_nonblock s1, :try_write_nonblock, "a" * 100000
n += write_nonblock s1, :try_write_nonblock, "b" * 100000
n += write_nonblock s1, :try_write_nonblock, "c" * 100000
n += write_nonblock s1, :try_write_nonblock, "d" * 100000
n += write_nonblock s1, :try_write_nonblock, "e" * 100000
n += write_nonblock s1, :try_write_nonblock, "f" * 100000
s1.close
assert_equal(n, s2.read.length)
}
end
def test_write_nonblock_with_buffered_data
ssl_pair {|s1, s2|
s1.write "foo"
......
}
end
def test_try_write_nonblock_with_buffered_data
ssl_pair {|s1, s2|
s1.write "foo"
s1.try_write_nonblock("bar")
s1.write "baz"
s1.close
assert_equal("foobarbaz", s2.read)
}
end
def test_connect_accept_nonblock
host = "127.0.0.1"
port = 0
test/ruby/test_io.rb
}
end
def test_try_write_nonblock
skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
pipe(proc do |w|
w.try_write_nonblock(1)
w.close
end, proc do |r|
assert_equal("1", r.read)
end)
end
def test_read_nonblock_error
return if !have_nonblock?
skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
......
assert_kind_of(IO::WaitReadable, $!)
end
}
with_pipe {|r, w|
begin
r.read_nonblock 4096, ""
rescue Errno::EWOULDBLOCK
assert_kind_of(IO::WaitReadable, $!)
end
}
end
def test_try_read_nonblock
return if !have_nonblock?
skip "IO#try_read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
assert_equal [nil, :wait_readable], r.try_read_nonblock(4096)
w.puts "HI!"
assert_equal "HI!\n", r.try_read_nonblock(4096).first
w.close
assert_equal nil, r.try_read_nonblock(4096).first
}
end
def test_try_read_nonblock_with_buffer
return if !have_nonblock?
skip "IO#try_read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
assert_equal [nil, :wait_readable], r.try_read_nonblock(4096, "")
w.puts "HI!"
buf = "buf"
value = r.try_read_nonblock(4096, buf).first
assert_equal value, "HI!\n"
assert buf.equal?(value)
w.close
assert_equal nil, r.try_read_nonblock(4096, "").first
}
end
def test_write_nonblock_error
......
}
end
def test_try_write_nonblock
return if !have_nonblock?
skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
loop {
ret, err = w.try_write_nonblock "a"*100000
if err.is_a?(Symbol)
assert err == :wait_writable
break
end
}
}
end
def test_gets
pipe(proc do |w|
w.write "foobarbaz"
test/socket/test_nonblock.rb
s.close if s
end
def test_try_read_nonblock
c, s = tcp_pair
assert_equal :wait_readable, c.try_read_nonblock(100)
assert_equal :wait_readable, s.try_read_nonblock(100)
c.write("abc")
IO.select [s]
assert_equal("a", s.try_read_nonblock(1))
assert_equal("bc", s.try_read_nonblock(100))
assert_equal :wait_readable, s.try_read_nonblock(100)
ensure
c.close if c
s.close if s
end
=begin
def test_write_nonblock
c, s = tcp_pair
test/stringio/test_stringio.rb
f = StringIO.new("\u3042\u3044")
assert_raise(ArgumentError) { f.readpartial(-1) }
assert_raise(ArgumentError) { f.readpartial(1, 2, 3) }
assert_equal("\u3042\u3044", f.readpartial)
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.readpartial(100))
f.rewind
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.readpartial(f.size))
f.rewind
......
f = StringIO.new("\u3042\u3044")
assert_raise(ArgumentError) { f.read_nonblock(-1) }
assert_raise(ArgumentError) { f.read_nonblock(1, 2, 3) }
assert_equal("\u3042\u3044", f.read_nonblock)
assert_equal("\u3042\u3044".force_encoding("BINARY"), f.read_nonblock(100))
assert_raise(EOFError) { f.read_nonblock(10) }
f.rewind
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.read_nonblock(f.size))
end
def test_try_read_nonblock
f = StringIO.new("\u3042\u3044")
assert_raise(ArgumentError) { f.try_read_nonblock(-1) }
assert_raise(ArgumentError) { f.try_read_nonblock(1, 2, 3) }
assert_raise(ArgumentError) { f.try_read_nonblock }
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.try_read_nonblock(100).first)
assert_equal(nil, f.try_read_nonblock(10).first)
f.rewind
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.read_nonblock(f.size))
f.rewind
(9-9/9)