Project

General

Profile

Feature #5138 » try_nonblock.diff

wycats (Yehuda Katz), 08/02/2011 09:02 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
else
return ""
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
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;
......
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_ZERO_RETURN:
if (no_exception) { return Qnil; }
rb_eof_error();
case SSL_ERROR_WANT_WRITE:
if (no_exception) { return ID2SYM(rb_intern("write_would_block")); }
write_would_block(nonblock);
rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
if (no_exception) { return ID2SYM(rb_intern("read_would_block")); }
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 Qnil; }
rb_eof_error();
}
rb_sys_fail(0);
default:
ossl_raise(eSSLError, "SSL_read:");
......
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, :write_would_block,
* :read_would_block, or nil (for EOF)
* ssl.try_sysread_nonblock(length, buffer) => buffer, :write_would_block,
* :read_would_block, 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,
* :read_would_block or :write_would_block.
*/
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 ID2SYM(rb_intern("write_would_block")); }
write_would_block(nonblock);
rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
if (no_exception) { return ID2SYM(rb_intern("read_would_block")); }
read_would_block(nonblock);
rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
......
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, :read_would_block or
* :write_would_block
*
* Exactly the same as +syswrite_nonblock+, except that instead of
* raising an exception if the write would block, returns
* :read_would_block or :write_would_block.
*/
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
static VALUE
strio_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)) {
rb_eof_error();
......
return val;
}
/*
* call-seq:
* strio.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 Qnil; }
return val;
}
#define strio_syswrite strio_write
/*
......
rb_define_method(StringIO, "sysread", strio_sysread, -1);
rb_define_method(StringIO, "readpartial", strio_sysread, -1);
rb_define_method(StringIO, "read_nonblock", strio_sysread, -1);
rb_define_method(StringIO, "try_read_nonblock", strio_try_sysread, -1);
rb_define_method(StringIO, "write", strio_write, 1);
rb_define_method(StringIO, "<<", strio_addstr, 1);
io.c
}
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_mod_sys_fail(rb_mWaitReadable, "read would block");
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
if (no_exception)
return ID2SYM(rb_intern("read_would_block"));
else
rb_mod_sys_fail(rb_mWaitReadable, "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();
else
......
{
VALUE ret;
ret = io_getpartial(argc, argv, io, 1);
ret = io_getpartial(argc, argv, io, 1, 0);
if (NIL_P(ret))
rb_eof_error();
else
return ret;
}
/**
* call-seq:
* ios.try_read_nonblock(maxlen) -> string, nil, or :read_would_block
* ios.try_read_nonblock(maxlen, outbuf) -> outbuf, nil, or :read_would_block
*
* +try_read_nonblock+ is identical to +read_nonblock+,
* except that instead of raising exceptions, blocking
* calls will return :read_would_block, 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 Qnil;
else
return ret;
}
static VALUE
io_write_nonblock(VALUE io, VALUE str, int no_exception)
{
rb_io_t *fptr;
long n;
rb_secure(4);
if (TYPE(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("write_would_block"));
rb_mod_sys_fail(rb_mWaitWritable, "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;
rb_secure(4);
if (TYPE(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)
rb_mod_sys_fail(rb_mWaitWritable, "write would block");
rb_sys_fail_path(fptr->pathv);
}
return io_write_nonblock(io, str, 0);
}
return LONG2FIX(n);
/*
* call-seq:
* ios.try_write_nonblock(string) -> integer or :write_would_block
*
* Works exactly like write_nonblock, with one exception:
*
* * if the write would block, <code>try_write_nonblock</code> returns
* :write_would_block rather than raising IO::WaitWritable
*/
static VALUE
rb_io_try_write_nonblock(VALUE io, VALUE str)
{
return io_write_nonblock(io, str, 1);
}
/*
......
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 :read_would_block, s2.try_read_nonblock(10)
s1.write "abc\ndef\n"
IO.select([s2])
assert_equal("ab", s2.try_read_nonblock(2))
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))
}
end
def write_nonblock(socket, meth, str)
ret = socket.send(meth, str)
ret.is_a?(Symbol) ? 0 : ret
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)
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 :read_would_block, r.try_read_nonblock(4096)
w.puts "HI!"
assert_equal "HI!\n", r.try_read_nonblock(4096)
w.close
assert_equal nil, r.try_read_nonblock(4096)
}
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 :read_would_block, r.try_read_nonblock(4096, "")
w.puts "HI!"
buf = "buf"
value = r.try_read_nonblock(4096, buf)
assert_equal value, "HI!\n"
assert buf.equal?(value)
w.close
assert_equal nil, r.try_read_nonblock(4096, "")
}
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 = w.try_write_nonblock "a"*100000
if ret.is_a?(Symbol)
assert ret == :write_would_block
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 :read_would_block, c.try_read_nonblock(100)
assert_equal :read_would_block, 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 :read_would_block, 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_raise(ArgumentError) { 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))
end
......
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_raise(ArgumentError) { 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))
assert_equal(nil, f.try_read_nonblock(10))
f.rewind
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.read_nonblock(f.size))
end
(2-2/9)