about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-06-15 08:30:03 +0000
committerEric Wong <normalperson@yhbt.net>2011-06-15 08:30:03 +0000
commit8fe21f6758bb877efacce1fa6573e72625252585 (patch)
treed39d394f990fe8ab074ed7d8757065eb20a9bd6a
parent9159f70862e3e6a76d821c4a70bc68a603793a49 (diff)
downloadkgio-8fe21f6758bb877efacce1fa6573e72625252585.tar.gz
IO.select can handle fd >= 1024 safely in some Rubies while
fd_set may not.  We could use rb_thread_fd_select(), but
rb_wait_for_single_fd() is available now so the former
is not worth the maintenance hassle.
-rw-r--r--ext/kgio/time_interval.h71
-rw-r--r--ext/kgio/wait.c55
-rw-r--r--ext/kgio/wait_for_single_fd.h46
3 files changed, 37 insertions, 135 deletions
diff --git a/ext/kgio/time_interval.h b/ext/kgio/time_interval.h
deleted file mode 100644
index 89f5556..0000000
--- a/ext/kgio/time_interval.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifdef HAVE_RB_TIME_INTERVAL
-/* not declared in public headers for Ruby <= 1.9.2 */
-struct timeval rb_time_interval(VALUE num);
-#else
-#include <math.h>
-#ifndef NUM2TIMET
-#  define NUM2TIMET NUM2INT
-#endif
-#ifndef RFLOAT_VALUE
-#  define RFLOAT_VALUE(f) (RFLOAT(f)->value)
-#endif
-
-static void negative_interval(void)
-{
-        rb_raise(rb_eArgError, "time interval must be positive");
-}
-
-static struct timeval kgio_time_interval(VALUE num)
-{
-        struct timeval tv;
-
-        switch (TYPE(num)) {
-        case T_FIXNUM:
-        case T_BIGNUM:
-                tv.tv_sec = NUM2TIMET(num);
-                if (tv.tv_sec < 0)
-                        negative_interval();
-                tv.tv_usec = 0;
-                break;
-        case T_FLOAT: {
-                double f, d;
-                double val = RFLOAT_VALUE(num);
-
-                if (val < 0.0)
-                        negative_interval();
-
-                d = modf(val, &f);
-                if (d >= 0) {
-                        tv.tv_usec = (long)(d * 1e6 + 0.5);
-                } else {
-                        tv.tv_usec = (long)(-d * 1e6 + 0.5);
-                        if (tv.tv_usec > 0) {
-                                tv.tv_usec = 1000000 - tv.tv_usec;
-                                f -= 1;
-                        }
-                }
-                tv.tv_sec = (time_t)f;
-                if (f != tv.tv_sec)
-                        rb_raise(rb_eRangeError, "%f out of range", val);
-        }
-                break;
-        default: {
-                VALUE f;
-                VALUE ary = rb_funcall(num, rb_intern("divmod"), 1, INT2FIX(1));
-
-                Check_Type(ary, T_ARRAY);
-
-                tv.tv_sec = NUM2TIMET(rb_ary_entry(ary, 0));
-                f = rb_ary_entry(ary, 1);
-                f = rb_funcall(f, '*', 1, INT2FIX(1000000));
-                tv.tv_usec = NUM2LONG(f);
-
-                if (tv.tv_sec < 0)
-                        negative_interval();
-
-        }
-        }
-        return tv;
-}
-#define rb_time_interval(v) kgio_time_interval(v)
-#endif /* HAVE_RB_TIME_INTERVAL */
diff --git a/ext/kgio/wait.c b/ext/kgio/wait.c
index 68ad99f..fe3896d 100644
--- a/ext/kgio/wait.c
+++ b/ext/kgio/wait.c
@@ -1,23 +1,42 @@
 #include "kgio.h"
-#include "time_interval.h"
-#include "wait_for_single_fd.h"
-
 static ID id_wait_rd, id_wait_wr;
 
-static int kgio_io_wait(int argc, VALUE *argv, VALUE self, int events)
+#if defined(HAVE_RB_TIME_INTERVAL) && defined(HAVE_RB_WAIT_FOR_SINGLE_FD)
+static int kgio_timedwait(VALUE self, VALUE timeout, int write_p)
+{
+        struct timeval tv = rb_time_interval(timeout);
+        int events = write_p ? RB_WAITFD_OUT : RB_WAITFD_IN;
+
+        return rb_wait_for_single_fd(my_fileno(self), events, &tv);
+}
+#else  /* ! (HAVE_RB_TIME_INTERVAL && HAVE_RB_WAIT_FOR_SINGLE_FD) */
+static int kgio_timedwait(VALUE self, VALUE timeout, int write_p)
 {
-        int fd = my_fileno(self);
-        VALUE t;
-        struct timeval *tp;
-        struct timeval tv;
-
-        if (rb_scan_args(argc, argv, "01", &t) == 0) {
-                tp = NULL;
-        } else {
-                tv = rb_time_interval(t);
-                tp = &tv;
-        }
-        return rb_wait_for_single_fd(fd, events, tp);
+        VALUE argv[4];
+        VALUE set = rb_ary_new3(1, self);
+
+        argv[0] = write_p ? Qnil : set;
+        argv[1] = write_p ? set : Qnil;
+        argv[2] = Qnil;
+        argv[3] = timeout;
+
+        set = rb_funcall2(rb_cIO, rb_intern("select"), 4, argv);
+        return NIL_P(set) ? 0 : 1;
+}
+#endif /* ! (HAVE_RB_TIME_INTERVAL && HAVE_RB_WAIT_FOR_SINGLE_FD) */
+
+static int kgio_wait(int argc, VALUE *argv, VALUE self, int write_p)
+{
+        int fd;
+        VALUE timeout;
+
+        if (rb_scan_args(argc, argv, "01", &timeout) == 1 && !NIL_P(timeout))
+                return kgio_timedwait(self, timeout, write_p);
+
+        fd = my_fileno(self);
+        errno = EAGAIN;
+        write_p ? rb_io_wait_writable(fd) : rb_io_wait_readable(fd);
+        return 1;
 }
 
 /*
@@ -39,7 +58,7 @@ static int kgio_io_wait(int argc, VALUE *argv, VALUE self, int events)
  */
 static VALUE kgio_wait_readable(int argc, VALUE *argv, VALUE self)
 {
-        int r = kgio_io_wait(argc, argv, self, RB_WAITFD_IN);
+        int r = kgio_wait(argc, argv, self, 0);
 
         if (r < 0) rb_sys_fail("kgio_wait_readable");
         return r == 0 ? Qnil : self;
@@ -59,7 +78,7 @@ static VALUE kgio_wait_readable(int argc, VALUE *argv, VALUE self)
  */
 static VALUE kgio_wait_writable(int argc, VALUE *argv, VALUE self)
 {
-        int r = kgio_io_wait(argc, argv, self, RB_WAITFD_OUT);
+        int r = kgio_wait(argc, argv, self, 1);
 
         if (r < 0) rb_sys_fail("kgio_wait_writable");
         return r == 0 ? Qnil : self;
diff --git a/ext/kgio/wait_for_single_fd.h b/ext/kgio/wait_for_single_fd.h
deleted file mode 100644
index 8e37318..0000000
--- a/ext/kgio/wait_for_single_fd.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* 1.9.3 uses ppoll() for this */
-#ifndef HAVE_RB_WAIT_FOR_SINGLE_FD
-#ifdef HAVE_SYS_SELECT_H
-#  include <sys/select.h>
-#endif
-
-#if defined(HAVE_POLL)
-#  include <poll.h>
-#  define RB_WAITFD_IN  POLLIN
-#  define RB_WAITFD_PRI POLLPRI
-#  define RB_WAITFD_OUT POLLOUT
-#else
-#  define RB_WAITFD_IN  0x001
-#  define RB_WAITFD_PRI 0x002
-#  define RB_WAITFD_OUT 0x004
-#endif
-
-static int kgio_wait_for_single_fd(int fd, int events, struct timeval *tv)
-{
-        fd_set fds;
-        fd_set *rfds;
-        fd_set *wfds;
-        int r;
-
-        FD_ZERO(&fds);
-        FD_SET(fd, &fds);
-
-        if (events == RB_WAITFD_IN) {
-                rfds = &fds;
-                wfds = NULL;
-        } else if (events == RB_WAITFD_OUT) {
-                rfds = NULL;
-                wfds = &fds;
-        } else {
-                rb_bug("incomplete rb_wait_for_single_fd emulation");
-        }
-
-        r = rb_thread_select(fd + 1, rfds, wfds, NULL, tv);
-        if (r <= 0)
-                return r;
-        return events;
-        rb_bug("rb_wait_for_single_fd emulation bug");
-}
-#define rb_wait_for_single_fd(fd,events,tv) \
-        kgio_wait_for_single_fd((fd),(events),(tv))
-#endif