mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Fix #6154 by introducing new EAGAIN/EWOULDBLOCK/EINPROGRESS
subclasses that include WaitReadable or WaitWritable rather than extending them into the exception object each time. * error.c: Capture EGAIN, EWOULDBLOCK, EINPROGRESS exceptions and export them for use in WaitReadable/Writable exceptions. * io.c: Create versions of EAGAIN, EWOULDBLOCK, EINPROGRESS that include WaitReadable and WaitWritable. Add rb_readwrite_sys_fail for nonblocking failures using those exceptions. Use that function in io_getpartial and io_write_nonblock instead of rb_mod_sys_fail * ext/openssl/ossl_ssl.c: Add new SSLError subclasses that include WaitReadable and WaitWritable. Use those classes for write_would_block and read_would_block instead of rb_mod_sys_fail. * ext/socket/ancdata.c: Use rb_readwrite_sys_fail instead of rb_mod_sys_fail in bsock_sendmsg_internal and bsock_recvmsg_internal. * ext/socket/init.c: Use rb_readwrite_sys_fail instead of rb_mod_sys_fail in rsock_s_recvfrom_nonblock and rsock_s_connect_nonblock. * ext/socket/socket.c: Use rb_readwrite_sys_fail instead of rb_mod_sys_fail in sock_connect_nonblock. * include/ruby/ruby.h: Export rb_readwrite_sys_fail for use instead of rb_mod_sys_fail. Introduce new constants RB_IO_WAIT_READABLE and RB_IO_WAIT_WRITABLE for first arg to rb_readwrite_sys_fail. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40195 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
46eddae1b4
commit
0626d9b91c
10 changed files with 152 additions and 14 deletions
24
ChangeLog
24
ChangeLog
|
@ -1,3 +1,27 @@
|
|||
Tue Apr 9 04:57:59 JST 2013 Charles Oliver Nutter <headius@headius.com>
|
||||
|
||||
* error.c: Capture EGAIN, EWOULDBLOCK, EINPROGRESS exceptions and
|
||||
export them for use in WaitReadable/Writable exceptions.
|
||||
* io.c: Create versions of EAGAIN, EWOULDBLOCK, EINPROGRESS that
|
||||
include WaitReadable and WaitWritable. Add rb_readwrite_sys_fail
|
||||
for nonblocking failures using those exceptions. Use that
|
||||
function in io_getpartial and io_write_nonblock instead of
|
||||
rb_mod_sys_fail
|
||||
* ext/openssl/ossl_ssl.c: Add new SSLError subclasses that include
|
||||
WaitReadable and WaitWritable. Use those classes for
|
||||
write_would_block and read_would_block instead of rb_mod_sys_fail.
|
||||
* ext/socket/ancdata.c: Use rb_readwrite_sys_fail instead of
|
||||
rb_mod_sys_fail in bsock_sendmsg_internal and
|
||||
bsock_recvmsg_internal.
|
||||
* ext/socket/init.c: Use rb_readwrite_sys_fail instead of
|
||||
rb_mod_sys_fail in rsock_s_recvfrom_nonblock and
|
||||
rsock_s_connect_nonblock.
|
||||
* ext/socket/socket.c: Use rb_readwrite_sys_fail instead of
|
||||
rb_mod_sys_fail in sock_connect_nonblock.
|
||||
* include/ruby/ruby.h: Export rb_readwrite_sys_fail for use instead
|
||||
of rb_mod_sys_fail. Introduce new constants RB_IO_WAIT_READABLE and
|
||||
RB_IO_WAIT_WRITABLE for first arg to rb_readwrite_sys_fail.
|
||||
|
||||
Tue Apr 9 02:44:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* ext/socket/extconf.rb: $defs needs -D or -U. nothing is added
|
||||
|
|
22
error.c
22
error.c
|
@ -39,6 +39,10 @@
|
|||
#define WEXITSTATUS(status) (status)
|
||||
#endif
|
||||
|
||||
VALUE rb_eEAGAIN;
|
||||
VALUE rb_eEWOULDBLOCK;
|
||||
VALUE rb_eEINPROGRESS;
|
||||
|
||||
extern const char ruby_description[];
|
||||
|
||||
#define REPORTBUG_MSG \
|
||||
|
@ -1183,6 +1187,24 @@ set_syserr(int n, const char *name)
|
|||
|
||||
if (!st_lookup(syserr_tbl, n, &error)) {
|
||||
error = rb_define_class_under(rb_mErrno, name, rb_eSystemCallError);
|
||||
|
||||
/* capture nonblock errnos for WaitReadable/WaitWritable subclasses */
|
||||
switch (n) {
|
||||
case EAGAIN:
|
||||
rb_eEAGAIN = error;
|
||||
|
||||
#if EAGAIN != EWOULDBLOCK
|
||||
break;
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
|
||||
rb_eEWOULDBLOCK = error;
|
||||
break;
|
||||
case EINPROGRESS:
|
||||
rb_eEINPROGRESS = error;
|
||||
break;
|
||||
}
|
||||
|
||||
rb_define_const(error, "Errno", INT2NUM(n));
|
||||
st_add_direct(syserr_tbl, n, error);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ VALUE eSSLError;
|
|||
VALUE cSSLContext;
|
||||
VALUE cSSLSocket;
|
||||
|
||||
static VALUE eSSLErrorWaitReadable;
|
||||
static VALUE eSSLErrorWaitWritable;
|
||||
|
||||
#define ossl_sslctx_set_cert(o,v) rb_iv_set((o),"@cert",(v))
|
||||
#define ossl_sslctx_set_key(o,v) rb_iv_set((o),"@key",(v))
|
||||
#define ossl_sslctx_set_client_ca(o,v) rb_iv_set((o),"@client_ca",(v))
|
||||
|
@ -1230,8 +1233,7 @@ static void
|
|||
write_would_block(int nonblock)
|
||||
{
|
||||
if (nonblock) {
|
||||
VALUE exc = ossl_exc_new(eSSLError, "write would block");
|
||||
rb_extend_object(exc, rb_mWaitWritable);
|
||||
VALUE exc = ossl_exc_new(eSSLErrorWaitReadable, "write would block");
|
||||
rb_exc_raise(exc);
|
||||
}
|
||||
}
|
||||
|
@ -1240,8 +1242,7 @@ static void
|
|||
read_would_block(int nonblock)
|
||||
{
|
||||
if (nonblock) {
|
||||
VALUE exc = ossl_exc_new(eSSLError, "read would block");
|
||||
rb_extend_object(exc, rb_mWaitReadable);
|
||||
VALUE exc = ossl_exc_new(eSSLErrorWaitReadable, "read would block");
|
||||
rb_exc_raise(exc);
|
||||
}
|
||||
}
|
||||
|
@ -1846,6 +1847,10 @@ Init_ossl_ssl()
|
|||
* Generic error class raised by SSLSocket and SSLContext.
|
||||
*/
|
||||
eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError);
|
||||
eSSLErrorWaitReadable = rb_define_class_under(mSSL, "SSLErrorWaitReadable", eSSLError);
|
||||
rb_include_module(eSSLErrorWaitReadable, rb_mWaitReadable);
|
||||
eSSLErrorWaitWritable = rb_define_class_under(mSSL, "SSLErrorWaitWritable", eSSLError);
|
||||
rb_include_module(eSSLErrorWaitWritable, rb_mWaitWritable);
|
||||
|
||||
Init_ossl_ssl_session();
|
||||
|
||||
|
|
|
@ -1285,7 +1285,7 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
|
|||
|
||||
if (ss == -1) {
|
||||
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
|
||||
rb_mod_sys_fail(rb_mWaitWritable, "sendmsg(2) would block");
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "sendmsg(2) would block");
|
||||
rb_sys_fail("sendmsg(2)");
|
||||
}
|
||||
|
||||
|
@ -1600,7 +1600,7 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
|
|||
|
||||
if (ss == -1) {
|
||||
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
|
||||
rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block");
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvmsg(2) would block");
|
||||
#if defined(HAVE_ST_MSG_CONTROL)
|
||||
if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
|
||||
/*
|
||||
|
|
|
@ -222,7 +222,7 @@ rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type
|
|||
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
rb_mod_sys_fail(rb_mWaitReadable, "recvfrom(2) would block");
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
|
||||
}
|
||||
rb_sys_fail("recvfrom(2)");
|
||||
}
|
||||
|
@ -541,7 +541,7 @@ rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, s
|
|||
#if defined EPROTO
|
||||
case EPROTO:
|
||||
#endif
|
||||
rb_mod_sys_fail(rb_mWaitReadable, "accept(2) would block");
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "accept(2) would block");
|
||||
}
|
||||
rb_sys_fail("accept(2)");
|
||||
}
|
||||
|
|
|
@ -446,7 +446,7 @@ sock_connect_nonblock(VALUE sock, VALUE addr)
|
|||
n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr));
|
||||
if (n < 0) {
|
||||
if (errno == EINPROGRESS)
|
||||
rb_mod_sys_fail(rb_mWaitWritable, "connect(2) would block");
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "connect(2) would block");
|
||||
rsock_sys_fail_raddrinfo_or_sockaddr("connect(2)", addr, rai);
|
||||
}
|
||||
|
||||
|
|
|
@ -1354,6 +1354,7 @@ NORETURN(void rb_sys_fail(const char*));
|
|||
NORETURN(void rb_sys_fail_str(VALUE));
|
||||
NORETURN(void rb_mod_sys_fail(VALUE, const char*));
|
||||
NORETURN(void rb_mod_sys_fail_str(VALUE, VALUE));
|
||||
NORETURN(void rb_readwrite_sys_fail(int, const char*));
|
||||
NORETURN(void rb_iter_break(void));
|
||||
NORETURN(void rb_iter_break_value(VALUE));
|
||||
NORETURN(void rb_exit(int));
|
||||
|
@ -1373,6 +1374,10 @@ PRINTF_ARGS(void rb_sys_warning(const char*, ...), 1, 2);
|
|||
PRINTF_ARGS(void rb_warn(const char*, ...), 1, 2);
|
||||
PRINTF_ARGS(void rb_compile_warn(const char *, int, const char*, ...), 3, 4);
|
||||
|
||||
/* for rb_readwrite_sys_fail first argument */
|
||||
#define RB_IO_WAIT_READABLE 0
|
||||
#define RB_IO_WAIT_WRITABLE 1
|
||||
|
||||
typedef VALUE rb_block_call_func(VALUE, VALUE, int, VALUE*);
|
||||
|
||||
VALUE rb_each(VALUE);
|
||||
|
|
80
io.c
80
io.c
|
@ -133,6 +133,16 @@ VALUE rb_eEOFError;
|
|||
VALUE rb_eIOError;
|
||||
VALUE rb_mWaitReadable;
|
||||
VALUE rb_mWaitWritable;
|
||||
extern VALUE rb_eEAGAIN;
|
||||
extern VALUE rb_eEWOULDBLOCK;
|
||||
extern VALUE rb_eEINPROGRESS;
|
||||
|
||||
static VALUE rb_eEAGAINWaitReadable;
|
||||
static VALUE rb_eEAGAINWaitWritable;
|
||||
static VALUE rb_eEWOULDBLOCKWaitReadable;
|
||||
static VALUE rb_eEWOULDBLOCKWaitWritable;
|
||||
static VALUE rb_eEINPROGRESSWaitWritable;
|
||||
static VALUE rb_eEINPROGRESSWaitReadable;
|
||||
|
||||
VALUE rb_stdin, rb_stdout, rb_stderr;
|
||||
VALUE rb_deferr; /* rescue VIM plugin */
|
||||
|
@ -2355,6 +2365,9 @@ rb_io_set_nonblock(rb_io_t *fptr)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_readwrite_sys_fail(int writable, const char *mesg);
|
||||
|
||||
static VALUE
|
||||
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
|
||||
{
|
||||
|
@ -2393,7 +2406,7 @@ io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
|
|||
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");
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "read would block");
|
||||
rb_sys_fail_path(fptr->pathv);
|
||||
}
|
||||
}
|
||||
|
@ -2612,7 +2625,7 @@ rb_io_write_nonblock(VALUE io, VALUE str)
|
|||
|
||||
if (n == -1) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
rb_mod_sys_fail(rb_mWaitWritable, "write would block");
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
|
||||
rb_sys_fail_path(fptr->pathv);
|
||||
}
|
||||
|
||||
|
@ -11450,6 +11463,50 @@ argf_write(VALUE argf, VALUE str)
|
|||
return rb_io_write(argf_write_io(argf), str);
|
||||
}
|
||||
|
||||
void
|
||||
rb_readwrite_sys_fail(int writable, const char *mesg)
|
||||
{
|
||||
VALUE arg;
|
||||
int n = errno;
|
||||
arg = mesg ? rb_str_new2(mesg) : Qnil;
|
||||
if (writable == RB_IO_WAIT_WRITABLE) {
|
||||
switch (n) {
|
||||
case EAGAIN:
|
||||
rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEAGAINWaitWritable));
|
||||
break;
|
||||
#if EAGAIN != EWOULDBLOCK
|
||||
case EWOULDBLOCK:
|
||||
rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEWOULDBLOCKWaitWritable));
|
||||
break;
|
||||
#endif
|
||||
case EINPROGRESS:
|
||||
rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEINPROGRESSWaitWritable));
|
||||
break;
|
||||
default:
|
||||
rb_mod_sys_fail_str(rb_mWaitWritable, arg);
|
||||
}
|
||||
}
|
||||
else if (writable == RB_IO_WAIT_READABLE) {
|
||||
switch (n) {
|
||||
case EAGAIN:
|
||||
rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEAGAINWaitReadable));
|
||||
break;
|
||||
#if EAGAIN != EWOULDBLOCK
|
||||
case EWOULDBLOCK:
|
||||
rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEWOULDBLOCKWaitReadable));
|
||||
break;
|
||||
#endif
|
||||
case EINPROGRESS:
|
||||
rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEINPROGRESSWaitReadable));
|
||||
break;
|
||||
default:
|
||||
rb_mod_sys_fail_str(rb_mWaitReadable, arg);
|
||||
}
|
||||
} else {
|
||||
rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", writable);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-class: IOError
|
||||
*
|
||||
|
@ -11658,6 +11715,25 @@ Init_IO(void)
|
|||
|
||||
rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
|
||||
rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
|
||||
rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
|
||||
rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
|
||||
rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
|
||||
rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
|
||||
if (EAGAIN == EWOULDBLOCK) {
|
||||
rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
|
||||
rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
|
||||
rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
|
||||
rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
|
||||
} else {
|
||||
rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKRWaiteadable", rb_eEWOULDBLOCK);
|
||||
rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
|
||||
rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
|
||||
rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
|
||||
}
|
||||
rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
|
||||
rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
|
||||
rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
|
||||
rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
|
||||
|
||||
#if 0
|
||||
/* This is necessary only for forcing rdoc handle File::open */
|
||||
|
|
|
@ -141,7 +141,7 @@ class OpenSSL::TestPair < Test::Unit::TestCase
|
|||
def test_read_nonblock
|
||||
ssl_pair {|s1, s2|
|
||||
err = nil
|
||||
assert_raise(OpenSSL::SSL::SSLError) {
|
||||
assert_raise(OpenSSL::SSL::SSLErrorWaitReadable) {
|
||||
begin
|
||||
s2.read_nonblock(10)
|
||||
ensure
|
||||
|
|
|
@ -348,7 +348,13 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
|
|||
|
||||
def test_dgram_pair
|
||||
s1, s2 = UNIXSocket.pair(Socket::SOCK_DGRAM)
|
||||
assert_raise(Errno::EAGAIN) { s1.recv_nonblock(10) }
|
||||
begin
|
||||
s1.recv_nonblock(10)
|
||||
fail
|
||||
rescue => e
|
||||
assert(IO::EAGAINWaitReadable === e)
|
||||
assert(IO::WaitReadable === e)
|
||||
end
|
||||
s2.send("", 0)
|
||||
s2.send("haha", 0)
|
||||
s2.send("", 0)
|
||||
|
@ -357,7 +363,7 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
|
|||
assert_equal("haha", s1.recv(10))
|
||||
assert_equal("", s1.recv(10))
|
||||
assert_equal("", s1.recv(10))
|
||||
assert_raise(Errno::EAGAIN) { s1.recv_nonblock(10) }
|
||||
assert_raise(IO::EAGAINWaitReadable) { s1.recv_nonblock(10) }
|
||||
ensure
|
||||
s1.close if s1
|
||||
s2.close if s2
|
||||
|
|
Loading…
Reference in a new issue