about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--ext/sleepy_penguin/epoll.c53
-rw-r--r--ext/sleepy_penguin/eventfd.c26
-rw-r--r--ext/sleepy_penguin/inotify.c14
-rw-r--r--ext/sleepy_penguin/signalfd.c8
-rw-r--r--ext/sleepy_penguin/sleepy_penguin.h69
-rw-r--r--ext/sleepy_penguin/timerfd.c16
-rw-r--r--ext/sleepy_penguin/util.c122
-rw-r--r--test/test_epoll.rb29
-rw-r--r--test/test_eventfd.rb9
-rw-r--r--test/test_inotify.rb34
-rw-r--r--test/test_signalfd.rb10
-rw-r--r--test/test_timerfd.rb13
12 files changed, 279 insertions, 124 deletions
diff --git a/ext/sleepy_penguin/epoll.c b/ext/sleepy_penguin/epoll.c
index 38f9113..395bd7f 100644
--- a/ext/sleepy_penguin/epoll.c
+++ b/ext/sleepy_penguin/epoll.c
@@ -156,24 +156,11 @@ static void ep_check(struct rb_epoll *ep)
  */
 static VALUE init(int argc, VALUE *argv, VALUE self)
 {
-        int flags;
         struct rb_epoll *ep = ep_get(self);
         VALUE fl;
 
         rb_scan_args(argc, argv, "01", &fl);
-        if (NIL_P(fl)) {
-                flags = 0;
-        } else {
-                switch (TYPE(fl)) {
-                case T_FIXNUM:
-                case T_BIGNUM:
-                        flags = NUM2INT(fl);
-                        break;
-                default:
-                        rb_raise(rb_eArgError, "flags must be an integer");
-                }
-        }
-        ep->flags = flags;
+        ep->flags = rb_sp_get_flags(self, fl);
         my_epoll_create(ep);
 
         return self;
@@ -183,11 +170,11 @@ static VALUE ctl(VALUE self, VALUE io, VALUE flags, int op)
 {
         struct epoll_event event;
         struct rb_epoll *ep = ep_get(self);
-        int fd = my_fileno(io);
+        int fd = rb_sp_fileno(io);
         int rv;
 
         ep_check(ep);
-        event.events = NUM2UINT(flags);
+        event.events = rb_sp_get_uflags(self, flags);
         pack_event_data(&event, io);
 
         rv = epoll_ctl(ep->fd, op, fd, &event);
@@ -204,6 +191,7 @@ static VALUE ctl(VALUE self, VALUE io, VALUE flags, int op)
                 rb_ary_store(ep->marks, fd, io);
                 /* fall-through */
         case EPOLL_CTL_MOD:
+                flags = UINT2NUM(event.events);
                 rb_ary_store(ep->flag_cache, fd, flags);
                 break;
         case EPOLL_CTL_DEL:
@@ -222,12 +210,12 @@ static VALUE set(VALUE self, VALUE io, VALUE flags)
 {
         struct epoll_event event;
         struct rb_epoll *ep = ep_get(self);
-        int fd = my_fileno(io);
+        int fd = rb_sp_fileno(io);
         int rv;
         VALUE cur_io = rb_ary_entry(ep->marks, fd);
 
         ep_check(ep);
-        event.events = NUM2UINT(flags);
+        event.events = rb_sp_get_uflags(self, flags);
         pack_event_data(&event, io);
 
         if (cur_io == io) {
@@ -261,6 +249,7 @@ fallback_add:
                 }
                 rb_ary_store(ep->marks, fd, io);
         }
+        flags = UINT2NUM(event.events);
         rb_ary_store(ep->flag_cache, fd, flags);
 
         return INT2NUM(rv);
@@ -275,16 +264,16 @@ fallback_add:
 static VALUE delete(VALUE self, VALUE io)
 {
         struct rb_epoll *ep = ep_get(self);
-        int fd = my_fileno(io);
+        int fd = rb_sp_fileno(io);
         int rv;
         VALUE cur_io;
 
         ep_check(ep);
-        if (my_io_closed(io))
+        if (rb_sp_io_closed(io))
                 goto out;
 
         cur_io = rb_ary_entry(ep->marks, fd);
-        if (NIL_P(cur_io) || my_io_closed(cur_io))
+        if (NIL_P(cur_io) || rb_sp_io_closed(cur_io))
                 return Qnil;
 
         rv = epoll_ctl(ep->fd, EPOLL_CTL_DEL, fd, NULL);
@@ -576,7 +565,7 @@ static VALUE io_for(VALUE self, VALUE obj)
 {
         struct rb_epoll *ep = ep_get(self);
 
-        return rb_ary_entry(ep->marks, my_fileno(obj));
+        return rb_ary_entry(ep->marks, rb_sp_fileno(obj));
 }
 
 /*
@@ -590,7 +579,7 @@ static VALUE flags_for(VALUE self, VALUE obj)
 {
         struct rb_epoll *ep = ep_get(self);
 
-        return rb_ary_entry(ep->flag_cache, my_fileno(obj));
+        return rb_ary_entry(ep->flag_cache, rb_sp_fileno(obj));
 }
 
 /*
@@ -606,7 +595,7 @@ static VALUE include_p(VALUE self, VALUE obj)
 {
         struct rb_epoll *ep = ep_get(self);
 
-        return NIL_P(rb_ary_entry(ep->marks, my_fileno(obj))) ? Qfalse : Qtrue;
+        return NIL_P(rb_ary_entry(ep->marks, rb_sp_fileno(obj))) ? Qfalse : Qtrue;
 }
 
 /*
@@ -664,35 +653,35 @@ void sleepy_penguin_init_epoll(void)
         rb_define_const(cEpoll, "CLOEXEC", INT2NUM(EPOLL_CLOEXEC));
 
         /* watch for read/recv operations */
-        rb_define_const(cEpoll, "IN", INT2NUM(EPOLLIN));
+        rb_define_const(cEpoll, "IN", UINT2NUM(EPOLLIN));
 
         /* watch for write/send operations */
-        rb_define_const(cEpoll, "OUT", INT2NUM(EPOLLOUT));
+        rb_define_const(cEpoll, "OUT", UINT2NUM(EPOLLOUT));
 
 #ifdef EPOLLRDHUP
         /* watch a specified IO for shutdown(SHUT_WR) on the remote-end */
-        rb_define_const(cEpoll, "RDHUP", INT2NUM(EPOLLRDHUP));
+        rb_define_const(cEpoll, "RDHUP", UINT2NUM(EPOLLRDHUP));
 #endif
         /* watch for urgent read(2) data */
-        rb_define_const(cEpoll, "PRI", INT2NUM(EPOLLPRI));
+        rb_define_const(cEpoll, "PRI", UINT2NUM(EPOLLPRI));
 
         /*
          * watch for errors, there is no need to specify this,
          * it is always monitored when an IO is watched
          */
-        rb_define_const(cEpoll, "ERR", INT2NUM(EPOLLERR));
+        rb_define_const(cEpoll, "ERR", UINT2NUM(EPOLLERR));
 
         /*
          * watch for hangups, there is no need to specify this,
          * it is always monitored when an IO is watched
          */
-        rb_define_const(cEpoll, "HUP", INT2NUM(EPOLLHUP));
+        rb_define_const(cEpoll, "HUP", UINT2NUM(EPOLLHUP));
 
         /* notifications are only Edge Triggered, see epoll(7) */
-        rb_define_const(cEpoll, "ET", INT2NUM(EPOLLET));
+        rb_define_const(cEpoll, "ET", UINT2NUM((uint32_t)EPOLLET));
 
         /* unwatch the descriptor once any event has fired */
-        rb_define_const(cEpoll, "ONESHOT", INT2NUM(EPOLLONESHOT));
+        rb_define_const(cEpoll, "ONESHOT", UINT2NUM(EPOLLONESHOT));
 
         id_for_fd = rb_intern("for_fd");
         active = st_init_numtable();
diff --git a/ext/sleepy_penguin/eventfd.c b/ext/sleepy_penguin/eventfd.c
index 6c2f800..704df7e 100644
--- a/ext/sleepy_penguin/eventfd.c
+++ b/ext/sleepy_penguin/eventfd.c
@@ -4,16 +4,16 @@
 #include "nonblock.h"
 static ID id_for_fd;
 
-static VALUE create(int argc, VALUE *argv, VALUE klass)
+static VALUE s_new(int argc, VALUE *argv, VALUE klass)
 {
         VALUE _initval, _flags;
         unsigned initval;
-        int flags = 0;
+        int flags;
         int fd;
 
         rb_scan_args(argc, argv, "11", &_initval, &_flags);
         initval = NUM2UINT(_initval);
-        flags = NIL_P(_flags) ? 0 : NUM2INT(_flags);
+        flags = rb_sp_get_flags(klass, _flags);
 
         fd = eventfd(initval, flags);
         if (fd == -1) {
@@ -55,7 +55,7 @@ static VALUE incr(VALUE self, VALUE value)
         struct efd_args x;
         ssize_t w;
 
-        x.fd = my_fileno(self);
+        x.fd = rb_sp_fileno(self);
         x.val = (uint64_t)NUM2ULL(value);
 
 retry:
@@ -74,7 +74,7 @@ static VALUE getvalue(VALUE self)
         struct efd_args x;
         ssize_t w;
 
-        x.fd = my_fileno(self);
+        x.fd = rb_sp_fileno(self);
 
 retry:
         w = (ssize_t)rb_thread_blocking_region(efd_read, &x, RUBY_UBF_IO, 0);
@@ -90,7 +90,7 @@ retry:
 
 static VALUE incr(VALUE self, VALUE value)
 {
-        int fd = my_fileno(self);
+        int fd = rb_sp_fileno(self);
         uint64_t val = (uint64_t)NUM2ULL(value);
         ssize_t w;
 
@@ -108,7 +108,7 @@ retry:
 
 static VALUE getvalue(VALUE self)
 {
-        int fd = my_fileno(self);
+        int fd = rb_sp_fileno(self);
         uint64_t val;
         ssize_t r;
 
@@ -127,7 +127,7 @@ retry:
 
 static VALUE getvalue_nonblock(VALUE self)
 {
-        int fd = my_fileno(self);
+        int fd = rb_sp_fileno(self);
         uint64_t val;
         ssize_t r;
 
@@ -141,7 +141,7 @@ static VALUE getvalue_nonblock(VALUE self)
 
 static VALUE incr_nonblock(VALUE self, VALUE value)
 {
-        int fd = my_fileno(self);
+        int fd = rb_sp_fileno(self);
         uint64_t val = (uint64_t)NUM2ULL(value);
         ssize_t w;
 
@@ -159,15 +159,15 @@ void sleepy_penguin_init_eventfd(void)
 
         mSleepyPenguin = rb_define_module("SleepyPenguin");
         cEventFD = rb_define_class_under(mSleepyPenguin, "EventFD", rb_cIO);
-        rb_define_singleton_method(cEventFD, "new", create, -1);
+        rb_define_singleton_method(cEventFD, "new", s_new, -1);
 #ifdef EFD_NONBLOCK
-        rb_define_const(cEventFD, "NONBLOCK", UINT2NUM(EFD_NONBLOCK));
+        rb_define_const(cEventFD, "NONBLOCK", INT2NUM(EFD_NONBLOCK));
 #endif
 #ifdef EFD_CLOEXEC
-        rb_define_const(cEventFD, "CLOEXEC", UINT2NUM(EFD_CLOEXEC));
+        rb_define_const(cEventFD, "CLOEXEC", INT2NUM(EFD_CLOEXEC));
 #endif
 #ifdef EFD_SEMAPHORE
-        rb_define_const(cEventFD, "SEMAPHORE", UINT2NUM(EFD_SEMAPHORE));
+        rb_define_const(cEventFD, "SEMAPHORE", INT2NUM(EFD_SEMAPHORE));
 #endif
         rb_define_method(cEventFD, "value", getvalue, 0);
         rb_define_method(cEventFD, "incr", incr, 1);
diff --git a/ext/sleepy_penguin/inotify.c b/ext/sleepy_penguin/inotify.c
index f222429..28477c3 100644
--- a/ext/sleepy_penguin/inotify.c
+++ b/ext/sleepy_penguin/inotify.c
@@ -77,7 +77,7 @@ static VALUE s_new(int argc, VALUE *argv, VALUE klass)
         int fd;
 
         rb_scan_args(argc, argv, "01", &_flags);
-        flags = NIL_P(_flags) ? 0 : NUM2INT(_flags);
+        flags = rb_sp_get_flags(klass, _flags);
 
         fd = inotify_init1(flags);
         if (fd == -1) {
@@ -106,9 +106,9 @@ static VALUE s_new(int argc, VALUE *argv, VALUE klass)
  */
 static VALUE add_watch(VALUE self, VALUE path, VALUE vmask)
 {
-        int fd = my_fileno(self);
+        int fd = rb_sp_fileno(self);
         const char *pathname = StringValueCStr(path);
-        uint32_t mask = NUM2UINT(vmask);
+        uint32_t mask = rb_sp_get_uflags(self, vmask);
         int rc = inotify_add_watch(fd, pathname, mask);
 
         if (rc == -1) {
@@ -132,7 +132,7 @@ static VALUE add_watch(VALUE self, VALUE path, VALUE vmask)
 static VALUE rm_watch(VALUE self, VALUE vwd)
 {
         uint32_t wd = NUM2UINT(vwd);
-        int fd = my_fileno(self);
+        int fd = rb_sp_fileno(self);
         int rc = inotify_rm_watch(fd, wd);
 
         if (rc == -1)
@@ -168,7 +168,7 @@ static VALUE event_new(struct inotify_event *e)
  */
 static VALUE take(int argc, VALUE *argv, VALUE self)
 {
-        int fd = my_fileno(self);
+        int fd = rb_sp_fileno(self);
         VALUE buf = rb_ivar_get(self, id_inotify_buf);
         VALUE tmp = rb_ivar_get(self, id_inotify_tmp);
         struct inotify_event *ptr;
@@ -328,7 +328,7 @@ void sleepy_penguin_init_inotify(void)
         IN(ONESHOT);
 
 /* for inotify_init1() */
-        IN(NONBLOCK);
-        IN(CLOEXEC);
+        rb_define_const(cInotify, "NONBLOCK", INT2NUM(IN_NONBLOCK));
+        rb_define_const(cInotify, "CLOEXEC", INT2NUM(IN_CLOEXEC));
 }
 #endif /* HAVE_SYS_INOTIFY_H */
diff --git a/ext/sleepy_penguin/signalfd.c b/ext/sleepy_penguin/signalfd.c
index 17cd41e..d7d7434 100644
--- a/ext/sleepy_penguin/signalfd.c
+++ b/ext/sleepy_penguin/signalfd.c
@@ -93,11 +93,11 @@ static VALUE update_bang(int argc, VALUE *argv, VALUE self)
         VALUE vmask, vflags;
         sigset_t mask;
         int flags;
-        int fd = my_fileno(self);
+        int fd = rb_sp_fileno(self);
         int rc;
 
         rb_scan_args(argc, argv, "02", &vmask, &vflags);
-        flags = NIL_P(vflags) ? cur_flags(fd) : NUM2INT(vflags);
+        flags = NIL_P(vflags) ? cur_flags(fd) : rb_sp_get_flags(self, vflags);
         value2sigset(&mask, vmask);
 
         rc = signalfd(fd, &mask, flags);
@@ -132,7 +132,7 @@ static VALUE s_new(int argc, VALUE *argv, VALUE klass)
         int fd;
 
         rb_scan_args(argc, argv, "02", &vmask, &vflags);
-        flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
+        flags = rb_sp_get_flags(klass, vflags);
         value2sigset(&mask, vmask);
 
         fd = signalfd(-1, &mask, flags);
@@ -205,7 +205,7 @@ static VALUE sfd_take(VALUE self)
         struct signalfd_siginfo *ssi = DATA_PTR(rv);
         ssize_t r;
 
-        ssi->ssi_fd = my_fileno(self);
+        ssi->ssi_fd = rb_sp_fileno(self);
         r = do_sfd_read(ssi);
         if (r < 0)
                 rb_sys_fail("read(signalfd)");
diff --git a/ext/sleepy_penguin/sleepy_penguin.h b/ext/sleepy_penguin/sleepy_penguin.h
index 50f6272..ce71f58 100644
--- a/ext/sleepy_penguin/sleepy_penguin.h
+++ b/ext/sleepy_penguin/sleepy_penguin.h
@@ -12,64 +12,13 @@
 #include <assert.h>
 #include <unistd.h>
 
-#if ! HAVE_RB_IO_T
-#  define rb_io_t OpenFile
-#endif
-
-#ifdef GetReadFile
-#  define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
-#else
-#  if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
-#    define FPTR_TO_FD(fptr) fileno(fptr->f)
-#  else
-#    define FPTR_TO_FD(fptr) fptr->fd
-#  endif
-#endif
-
-static int fixint_closed_p(VALUE io)
-{
-        return (fcntl(FIX2INT(io), F_GETFD) == -1 && errno == EBADF);
-}
-
-#if defined(RFILE) && defined(HAVE_ST_FD)
-static int my_rb_io_closed(VALUE io)
-{
-        return RFILE(io)->fptr->fd < 0;
-}
-#else
-static int my_rb_io_closed(VALUE io)
-{
-        return rb_funcall(io, rb_intern("closed?"), 0) == Qtrue;
-}
-#endif
-
-static int my_io_closed(VALUE io)
-{
-        switch (TYPE(io)) {
-        case T_FIXNUM:
-                return fixint_closed_p(io);
-        case T_FILE:
-                break;
-        default:
-                io = rb_convert_type(io, T_FILE, "IO", "to_io");
-        }
-
-        return my_rb_io_closed(io);
-}
-
-static int my_fileno(VALUE io)
-{
-        rb_io_t *fptr;
-
-        switch (TYPE(io)) {
-        case T_FIXNUM: return FIX2INT(io);
-        case T_FILE:
-                GetOpenFile(io, fptr);
-                return FPTR_TO_FD(fptr);
-        }
-        io = rb_convert_type(io, T_FILE, "IO", "to_io");
-        GetOpenFile(io, fptr);
-        return FPTR_TO_FD(fptr);
-}
-
+unsigned rb_sp_get_uflags(VALUE klass, VALUE flags);
+int rb_sp_get_flags(VALUE klass, VALUE flags);
+int rb_sp_io_closed(VALUE io);
+int rb_sp_fileno(VALUE io);
+
+#define get_uflags rb_sp_get_uflags
+#define get_flags rb_sp_get_flags
+#define my_io_closed rb_sp_io_closed
+#define my_fileno rb_sp_fileno
 #endif /* SLEEPY_PENGUIN_H */
diff --git a/ext/sleepy_penguin/timerfd.c b/ext/sleepy_penguin/timerfd.c
index 684291e..dccb255 100644
--- a/ext/sleepy_penguin/timerfd.c
+++ b/ext/sleepy_penguin/timerfd.c
@@ -7,12 +7,12 @@ static ID id_for_fd;
 static VALUE s_new(int argc, VALUE *argv, VALUE klass)
 {
         VALUE cid, fl;
-        int clockid, flags = 0;
+        int clockid, flags;
         int fd;
 
         rb_scan_args(argc, argv, "02", &cid, &fl);
-        clockid = NIL_P(cid) ? CLOCK_MONOTONIC : NUM2INT(cid);
-        flags = NIL_P(fl) ? 0 : NUM2INT(fl);
+        clockid = NIL_P(cid) ? CLOCK_MONOTONIC : rb_sp_get_flags(klass, cid);
+        flags = rb_sp_get_flags(klass, fl);
 
         fd = timerfd_create(clockid, flags);
         if (fd == -1) {
@@ -37,8 +37,8 @@ static VALUE itimerspec2ary(struct itimerspec *its)
 
 static VALUE settime(VALUE self, VALUE fl, VALUE interval, VALUE value)
 {
-        int fd = my_fileno(self);
-        int flags = NUM2INT(fl);
+        int fd = rb_sp_fileno(self);
+        int flags = rb_sp_get_flags(self, fl);
         struct itimerspec old, new;
 
         value2timespec(&new.it_interval, interval);
@@ -52,7 +52,7 @@ static VALUE settime(VALUE self, VALUE fl, VALUE interval, VALUE value)
 
 static VALUE gettime(VALUE self)
 {
-        int fd = my_fileno(self);
+        int fd = rb_sp_fileno(self);
         struct itimerspec curr;
 
         if (timerfd_gettime(fd, &curr) == -1)
@@ -74,7 +74,7 @@ static VALUE tfd_read(void *args)
 static VALUE expirations(VALUE self)
 {
         ssize_t r;
-        uint64_t buf = (int)my_fileno(self);
+        uint64_t buf = (int)rb_sp_fileno(self);
 
         r = (VALUE)rb_thread_blocking_region(tfd_read, &buf, RUBY_UBF_IO, 0);
         if (r == -1)
@@ -86,7 +86,7 @@ static VALUE expirations(VALUE self)
 #include "nonblock.h"
 static VALUE expirations(VALUE self)
 {
-        int fd = my_fileno(self);
+        int fd = rb_sp_fileno(self);
         uint64_t buf;
         ssize_t r;
 
diff --git a/ext/sleepy_penguin/util.c b/ext/sleepy_penguin/util.c
new file mode 100644
index 0000000..d8b27d4
--- /dev/null
+++ b/ext/sleepy_penguin/util.c
@@ -0,0 +1,122 @@
+#include "sleepy_penguin.h"
+
+static VALUE klass_for(VALUE klass)
+{
+        return (TYPE(klass) == T_CLASS) ? klass : CLASS_OF(klass);
+}
+
+int rb_sp_get_flags(VALUE klass, VALUE flags)
+{
+        switch (TYPE(flags)) {
+        case T_NIL: return 0;
+        case T_FIXNUM: return FIX2INT(flags);
+        case T_BIGNUM: return NUM2INT(flags);
+        case T_SYMBOL:
+                return NUM2INT(rb_const_get(klass_for(klass), SYM2ID(flags)));
+        case T_ARRAY: {
+                VALUE *ptr = RARRAY_PTR(flags);
+                long len = RARRAY_LEN(flags);
+                int rv = 0;
+
+                klass = klass_for(klass);
+                while (--len >= 0) {
+                        VALUE tmp = *ptr++;
+
+                        Check_Type(tmp, T_SYMBOL);
+                        tmp = rb_const_get(klass, SYM2ID(tmp));
+                        rv |= NUM2INT(tmp);
+                }
+                return rv;
+                }
+        }
+        rb_raise(rb_eTypeError, "invalid flags");
+        return 0;
+}
+
+unsigned rb_sp_get_uflags(VALUE klass, VALUE flags)
+{
+        switch (TYPE(flags)) {
+        case T_NIL: return 0;
+        case T_FIXNUM: return FIX2UINT(flags);
+        case T_BIGNUM: return NUM2UINT(flags);
+        case T_SYMBOL:
+                return NUM2UINT(rb_const_get(klass_for(klass), SYM2ID(flags)));
+        case T_ARRAY: {
+                VALUE *ptr = RARRAY_PTR(flags);
+                long len = RARRAY_LEN(flags);
+                unsigned rv = 0;
+
+                klass = klass_for(klass);
+                while (--len >= 0) {
+                        VALUE tmp = *ptr++;
+
+                        Check_Type(tmp, T_SYMBOL);
+                        tmp = rb_const_get(klass, SYM2ID(tmp));
+                        rv |= NUM2UINT(tmp);
+                }
+                return rv;
+                }
+        }
+        rb_raise(rb_eTypeError, "invalid flags");
+        return 0;
+}
+
+#if ! HAVE_RB_IO_T
+#  define rb_io_t OpenFile
+#endif
+
+#ifdef GetReadFile
+#  define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
+#else
+#  if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
+#    define FPTR_TO_FD(fptr) fileno(fptr->f)
+#  else
+#    define FPTR_TO_FD(fptr) fptr->fd
+#  endif
+#endif
+
+static int fixint_closed_p(VALUE io)
+{
+        return (fcntl(FIX2INT(io), F_GETFD) == -1 && errno == EBADF);
+}
+
+#if defined(RFILE) && defined(HAVE_ST_FD)
+static int my_rb_io_closed(VALUE io)
+{
+        return RFILE(io)->fptr->fd < 0;
+}
+#else
+static int my_rb_io_closed(VALUE io)
+{
+        return rb_funcall(io, rb_intern("closed?"), 0) == Qtrue;
+}
+#endif
+
+int rb_sp_io_closed(VALUE io)
+{
+        switch (TYPE(io)) {
+        case T_FIXNUM:
+                return fixint_closed_p(io);
+        case T_FILE:
+                break;
+        default:
+                io = rb_convert_type(io, T_FILE, "IO", "to_io");
+        }
+
+        return my_rb_io_closed(io);
+}
+
+int rb_sp_fileno(VALUE io)
+{
+        rb_io_t *fptr;
+
+        switch (TYPE(io)) {
+        case T_FIXNUM: return FIX2INT(io);
+        case T_FILE:
+                GetOpenFile(io, fptr);
+                return FPTR_TO_FD(fptr);
+        }
+        io = rb_convert_type(io, T_FILE, "IO", "to_io");
+        GetOpenFile(io, fptr);
+        return FPTR_TO_FD(fptr);
+}
diff --git a/test/test_epoll.rb b/test/test_epoll.rb
index 4c8dfa6..69e4f4c 100644
--- a/test/test_epoll.rb
+++ b/test/test_epoll.rb
@@ -14,6 +14,14 @@ class TestEpoll < Test::Unit::TestCase
     @ep = Epoll.new
   end
 
+  def test_constants
+    Epoll.constants.each do |const|
+      next if const.to_sym == :IO
+      nr = Epoll.const_get(const)
+      assert nr <= 0xffffffff, "#{const}=#{nr}"
+    end
+  end
+
   def test_cross_thread
     tmp = []
     Thread.new { sleep 0.100; @ep.add(@wr, Epoll::OUT) }
@@ -347,6 +355,27 @@ class TestEpoll < Test::Unit::TestCase
     assert_nil @ep.flags_for(@rd)
   end
 
+  def test_flags_for_sym
+    @ep.add @rd, :IN
+    assert_equal Epoll::IN, @ep.flags_for(@rd.fileno)
+    assert_equal Epoll::IN, @ep.flags_for(@rd)
+
+    @ep.del @rd
+    assert_nil @ep.flags_for(@rd.fileno)
+    assert_nil @ep.flags_for(@rd)
+  end
+
+  def test_flags_for_sym_ary
+    @ep.add @rd, [:IN, :ET]
+    expect = Epoll::IN | Epoll::ET
+    assert_equal expect, @ep.flags_for(@rd.fileno)
+    assert_equal expect, @ep.flags_for(@rd)
+
+    @ep.del @rd
+    assert_nil @ep.flags_for(@rd.fileno)
+    assert_nil @ep.flags_for(@rd)
+  end
+
   def test_include?
     assert ! @ep.include?(@rd)
     @ep.add @rd, Epoll::IN
diff --git a/test/test_eventfd.rb b/test/test_eventfd.rb
index 4780c48..7739448 100644
--- a/test/test_eventfd.rb
+++ b/test/test_eventfd.rb
@@ -27,6 +27,15 @@ class TestEventFD < Test::Unit::TestCase
     assert_equal(Fcntl::O_NONBLOCK, flags)
   end if defined?(EventFD::NONBLOCK)
 
+  def test_new_nonblock_cloexec_sym
+    efd = EventFD.new(0, [:NONBLOCK,:CLOEXEC])
+    flags = efd.fcntl(Fcntl::F_GETFL) & Fcntl::O_NONBLOCK
+    assert_equal(Fcntl::O_NONBLOCK, flags)
+
+    flags = efd.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC
+    assert_equal(Fcntl::FD_CLOEXEC, flags)
+  end if defined?(EventFD::NONBLOCK) && defined?(EventFD::CLOEXEC)
+
   def test_new_cloexec
     efd = EventFD.new(0, EventFD::CLOEXEC)
     flags = efd.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC
diff --git a/test/test_inotify.rb b/test/test_inotify.rb
index ab52b77..bbda16f 100644
--- a/test/test_inotify.rb
+++ b/test/test_inotify.rb
@@ -12,6 +12,17 @@ class TestInotify < Test::Unit::TestCase
     assert_kind_of(IO, ino)
   end
 
+  def test_constants
+    Inotify.constants.each do |const|
+      case const.to_sym
+      when :Event, :Enumerator
+      else
+        nr = Inotify.const_get(const)
+        assert nr <= 0xffffffff, "#{const}=#{nr}"
+      end
+    end
+  end
+
   def test_dup
     a = Inotify.new
     b = a.dup
@@ -59,4 +70,27 @@ class TestInotify < Test::Unit::TestCase
     assert_equal second_id, ino.take.object_id
     assert_nil ino.take(true)
   end
+
+  def test_add_take_symbols
+    ino = Inotify.new :CLOEXEC
+    tmp1 = Tempfile.new 'take'
+    tmp2 = Tempfile.new 'take'
+    wd = ino.add_watch File.dirname(tmp1.path), :MOVE
+    assert_kind_of Integer, wd
+    File.rename tmp1.path, tmp2.path
+    event = ino.take
+    assert_equal wd, event.wd
+    assert_kind_of Inotify::Event, event
+    assert_equal File.basename(tmp1.path), event.name
+    others = ino.instance_variable_get(:@inotify_tmp)
+    assert_kind_of Array, others
+    assert_equal 1, others.size
+    assert_equal File.basename(tmp2.path), others[0].name
+    assert_equal [ :MOVED_FROM ], event.events
+    assert_equal [ :MOVED_TO ], others[0].events
+    assert_equal wd, others[0].wd
+    second_id = others[0].object_id
+    assert_equal second_id, ino.take.object_id
+    assert_nil ino.take(true)
+  end
 end
diff --git a/test/test_signalfd.rb b/test/test_signalfd.rb
index 36486dc..5d6c9f4 100644
--- a/test/test_signalfd.rb
+++ b/test/test_signalfd.rb
@@ -13,6 +13,16 @@ class TestSignalFD < Test::Unit::TestCase
     @sfd.close if @sfd && ! @sfd.closed?
   end
 
+  def test_new_with_flags
+    @sfd = SignalFD.new(%w(USR1), [:CLOEXEC,:NONBLOCK])
+    assert_instance_of SignalFD, @sfd
+  end if defined?(SignalFD::CLOEXEC) && defined?(SignalFD::NONBLOCK)
+
+  def test_new_with_sym_flag
+    @sfd = SignalFD.new(%w(USR1), :CLOEXEC)
+    assert_instance_of SignalFD, @sfd
+  end if defined?(SignalFD::CLOEXEC)
+
   def test_take
     @sfd = SignalFD.new(%w(USR1), 0)
     pid = fork { sleep 0.01; Process.kill(:USR1, Process.ppid) }
diff --git a/test/test_timerfd.rb b/test/test_timerfd.rb
index 029f4e3..225a933 100644
--- a/test/test_timerfd.rb
+++ b/test/test_timerfd.rb
@@ -23,6 +23,12 @@ class TestTimerFD < Test::Unit::TestCase
     assert_equal(Fcntl::O_NONBLOCK, flags)
   end if defined?(TimerFD::NONBLOCK)
 
+  def test_create_nonblock_sym
+    tfd = TimerFD.new(:REALTIME, :NONBLOCK)
+    flags = tfd.fcntl(Fcntl::F_GETFL) & Fcntl::O_NONBLOCK
+    assert_equal(Fcntl::O_NONBLOCK, flags)
+  end if defined?(TimerFD::NONBLOCK)
+
   def test_create_cloexec
     tfd = TimerFD.new(TimerFD::REALTIME, TimerFD::CLOEXEC)
     flags = tfd.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC
@@ -35,4 +41,11 @@ class TestTimerFD < Test::Unit::TestCase
     sleep 0.01
     assert_equal 1, tfd.expirations
   end
+
+  def test_settime_symbol
+    tfd = TimerFD.new(:REALTIME)
+    assert_equal([0, 0], tfd.settime(:ABSTIME, 0, 0.01))
+    sleep 0.01
+    assert_equal 1, tfd.expirations
+  end
 end if defined?(SleepyPenguin::TimerFD)