From f1b497e601ed2acb54f75dc989d0a5ec7afebca0 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 18 Nov 2010 13:38:32 -0800 Subject: add default kgio_wait_*able methods It makes it easier for people to use certain overrides without killing other methods. This is the first step in fixing problems people were having with dalli 0.11.1+ while running Unicorn. --- ext/kgio/connect.c | 2 +- ext/kgio/kgio.h | 4 ++-- ext/kgio/read_write.c | 7 +++++-- ext/kgio/wait.c | 41 +++++++++++++++++++++++++++++++++++++++-- test/test_default_wait.rb | 21 +++++++++++++++++++++ 5 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 test/test_default_wait.rb diff --git a/ext/kgio/connect.c b/ext/kgio/connect.c index 8defa7e..1f670db 100644 --- a/ext/kgio/connect.c +++ b/ext/kgio/connect.c @@ -46,7 +46,7 @@ my_connect(VALUE klass, int io_wait, int domain, void *addr, socklen_t addrlen) if (io_wait) { errno = EAGAIN; - kgio_wait_writable(io, fd); + kgio_call_wait_writable(io, fd); } return io; } diff --git a/ext/kgio/kgio.h b/ext/kgio/kgio.h index 0c5b0d8..74c01b5 100644 --- a/ext/kgio/kgio.h +++ b/ext/kgio/kgio.h @@ -34,7 +34,7 @@ void init_kgio_read_write(void); void init_kgio_accept(void); void init_kgio_connect(void); -void kgio_wait_writable(VALUE io, int fd); -void kgio_wait_readable(VALUE io, int fd); +void kgio_call_wait_writable(VALUE io, int fd); +void kgio_call_wait_readable(VALUE io, int fd); #endif /* KGIO_H */ diff --git a/ext/kgio/read_write.c b/ext/kgio/read_write.c index 2e568c5..3b208fe 100644 --- a/ext/kgio/read_write.c +++ b/ext/kgio/read_write.c @@ -67,7 +67,7 @@ static int read_check(struct io_args *a, long n, const char *msg, int io_wait) rb_str_set_len(a->buf, 0); if (errno == EAGAIN) { if (io_wait) { - kgio_wait_readable(a->io, a->fd); + kgio_call_wait_readable(a->io, a->fd); /* buf may be modified in other thread/fiber */ rb_str_resize(a->buf, a->len); @@ -232,7 +232,7 @@ done: long written = RSTRING_LEN(a->buf) - a->len; if (io_wait) { - kgio_wait_writable(a->io, a->fd); + kgio_call_wait_writable(a->io, a->fd); /* buf may be modified in other thread/fiber */ a->len = RSTRING_LEN(a->buf) - written; @@ -352,6 +352,7 @@ void init_kgio_read_write(void) { VALUE mPipeMethods, mSocketMethods; VALUE mKgio = rb_define_module("Kgio"); + VALUE mWaiters = rb_const_get(mKgio, rb_intern("DefaultWaiters")); sym_wait_readable = ID2SYM(rb_intern("wait_readable")); sym_wait_writable = ID2SYM(rb_intern("wait_writable")); @@ -393,4 +394,6 @@ void init_kgio_read_write(void) eErrno_EPIPE = rb_const_get(rb_mErrno, rb_intern("EPIPE")); eErrno_ECONNRESET = rb_const_get(rb_mErrno, rb_intern("ECONNRESET")); + rb_include_module(mPipeMethods, mWaiters); + rb_include_module(mSocketMethods, mWaiters); } diff --git a/ext/kgio/wait.c b/ext/kgio/wait.c index d9266eb..9cfcbdb 100644 --- a/ext/kgio/wait.c +++ b/ext/kgio/wait.c @@ -2,8 +2,35 @@ static ID io_wait_rd, io_wait_wr; -void kgio_wait_readable(VALUE io, int fd) +/* + * avoiding rb_thread_select() or similar since rb_io_wait_*able can be + * made to use poll() later on. It's highly unlikely Ruby will move to + * use an edge-triggered event notification, so assign EAGAIN is safe... + */ +static VALUE force_wait_readable(VALUE self) +{ + errno = EAGAIN; + if (!rb_io_wait_readable(my_fileno(self))) + rb_sys_fail("wait readable"); + + return self; +} + +static VALUE force_wait_writable(VALUE self) { + errno = EAGAIN; + if (!rb_io_wait_writable(my_fileno(self))) + rb_sys_fail("wait writable"); + + return self; +} + +void kgio_call_wait_readable(VALUE io, int fd) +{ + /* + * we _NEVER_ set errno = EAGAIN here by default so we can work + * (or fail hard) with edge-triggered epoll() + */ if (io_wait_rd) { (void)rb_funcall(io, io_wait_rd, 0, 0); } else { @@ -12,8 +39,12 @@ void kgio_wait_readable(VALUE io, int fd) } } -void kgio_wait_writable(VALUE io, int fd) +void kgio_call_wait_writable(VALUE io, int fd) { + /* + * we _NEVER_ set errno = EAGAIN here by default so we can work + * (or fail hard) with edge-triggered epoll() + */ if (io_wait_wr) { (void)rb_funcall(io, io_wait_wr, 0, 0); } else { @@ -109,6 +140,12 @@ static VALUE wait_rd(VALUE mod) void init_kgio_wait(void) { VALUE mKgio = rb_define_module("Kgio"); + VALUE mWaiters = rb_define_module_under(mKgio, "DefaultWaiters"); + + rb_define_method(mWaiters, "kgio_wait_readable", + force_wait_readable, 0); + rb_define_method(mWaiters, "kgio_wait_writable", + force_wait_writable, 0); rb_define_singleton_method(mKgio, "wait_readable=", set_wait_rd, 1); rb_define_singleton_method(mKgio, "wait_writable=", set_wait_wr, 1); diff --git a/test/test_default_wait.rb b/test/test_default_wait.rb new file mode 100644 index 0000000..10033fe --- /dev/null +++ b/test/test_default_wait.rb @@ -0,0 +1,21 @@ +require 'test/unit' +require 'io/nonblock' +$-w = true +require 'kgio' + +class TestDefaultWait < Test::Unit::TestCase + + def test_socket_pair + a, b = Kgio::UNIXSocket.pair + assert_equal a, a.kgio_wait_writable + a.syswrite('.') + assert_equal b, b.kgio_wait_readable + end + + def test_pipe + a, b = Kgio::Pipe.new + assert_equal b, b.kgio_wait_writable + b.syswrite('.') + assert_equal a, a.kgio_wait_readable + end +end -- cgit v1.2.3-24-ge0c7