about summary refs log tree commit homepage
path: root/ext
diff options
context:
space:
mode:
authorEric Wong <e@yhbt.net>2011-03-10 02:12:46 +0000
committerEric Wong <normalperson@yhbt.net>2011-03-10 02:12:46 +0000
commit32bc376e494b5477b921b6d198b7aeda0c8efe12 (patch)
treefb63617355aa2a88a98b6209a727c9eb82d14d8e /ext
parent39d900abaebcb82aa2f2766b692ef558d44a9349 (diff)
downloadsleepy_penguin-32bc376e494b5477b921b6d198b7aeda0c8efe12.tar.gz
Arguments now take symbols and arrays of symbols just like the
SignalFD.new method.  This fixes some use of signed vs unsigned
integer conversions as well.
Diffstat (limited to 'ext')
-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
7 files changed, 184 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);
+}