about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@yhbt.net>2010-11-18 13:38:32 -0800
committerEric Wong <e@yhbt.net>2010-11-18 13:48:57 -0800
commitf1b497e601ed2acb54f75dc989d0a5ec7afebca0 (patch)
treee3b4341ff004c2720b9eeaaeac28b93c3efb87a6
parent827ad6b4fba768a5cac8fb4e83fbbf61cf7a3194 (diff)
downloadkgio-f1b497e601ed2acb54f75dc989d0a5ec7afebca0.tar.gz
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.
-rw-r--r--ext/kgio/connect.c2
-rw-r--r--ext/kgio/kgio.h4
-rw-r--r--ext/kgio/read_write.c7
-rw-r--r--ext/kgio/wait.c41
-rw-r--r--test/test_default_wait.rb21
5 files changed, 68 insertions, 7 deletions
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