about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-04-29 20:55:10 +0000
committerEric Wong <normalperson@yhbt.net>2013-04-29 21:01:02 +0000
commitda07e5676040d543c33720efae19f2a70e766a39 (patch)
treebd710cbd2327b8853938d911f25ad78da9d3d02e
parenta974d3acb4cf59696c71f82004e2b42d1c1903d9 (diff)
downloadsleepy_penguin-da07e5676040d543c33720efae19f2a70e766a39.tar.gz
Rubinius will not support RSTRUCT* macros, so converting the
structs to arrays is the least intrusive way to go about our
code.

ref: https://github.com/rubinius/rubinius/issues/494
-rw-r--r--ext/sleepy_penguin/kqueue.c70
-rw-r--r--test/test_kqueue_io.rb6
2 files changed, 56 insertions, 20 deletions
diff --git a/ext/sleepy_penguin/kqueue.c b/ext/sleepy_penguin/kqueue.c
index 78a13c3..155204b 100644
--- a/ext/sleepy_penguin/kqueue.c
+++ b/ext/sleepy_penguin/kqueue.c
@@ -24,6 +24,18 @@
 #  define NUM2USHORT(n) (short)NUM2UINT(n)
 #endif
 
+/*
+ * Rubinius does not support RSTRUCT_* in the C API:
+ * ref: https://github.com/rubinius/rubinius/issues/494
+ */
+#if defined(RUBINIUS)
+#  define RBX_STRUCT (1)
+#  define RSTRUCT_LEN(s) 0, rb_bug("RSTRUCT_LEN attempted in Rubinius")
+#  define RSTRUCT_PTR(s) NULL, rb_bug("RSTRUCT_PTR attempted in Rubinius")
+#else
+#  define RBX_STRUCT (0)
+#endif
+
 static const long NANO_PER_SEC = 1000000000;
 static ID id_for_fd;
 static VALUE mEv, mEvFilt, mNote, mVQ;
@@ -233,33 +245,42 @@ static void event_set(struct kevent *event, VALUE *chg)
         EV_SET(event, ident, filter, flags, fflags, data, udata);
 }
 
+/* sets ptr and len */
+static void unpack_event(VALUE **ptr, VALUE *len, VALUE *event)
+{
+        switch (TYPE(*event)) {
+        case T_STRUCT:
+                if (RBX_STRUCT) {
+                        *event = rb_funcall(*event, rb_intern("to_a"), 0, 0);
+                        /* fall-through to T_ARRAY */
+                } else {
+                        *len = RSTRUCT_LEN(*event);
+                        *ptr = RSTRUCT_PTR(*event);
+                        return;
+                }
+        case T_ARRAY:
+                *len = RARRAY_LEN(*event);
+                *ptr = RARRAY_PTR(*event);
+                return;
+        default:
+                rb_raise(rb_eTypeError, "unsupported type in changelist");
+        }
+}
+
 static void ary2eventlist(struct kevent *events, VALUE changelist)
 {
         VALUE *chg = RARRAY_PTR(changelist);
         long i = RARRAY_LEN(changelist);
+        VALUE event;
 
         for (; --i >= 0; chg++) {
                 VALUE clen;
                 VALUE *cptr;
 
-                switch (TYPE(*chg)) {
-                case T_STRUCT:
-                        clen = RSTRUCT_LEN(*chg);
-                        cptr = RSTRUCT_PTR(*chg);
-                        break;
-                case T_ARRAY:
-                        clen = RARRAY_LEN(*chg);
-                        cptr = RARRAY_PTR(*chg);
-                        break;
-                default:
-                        rb_raise(rb_eTypeError,
-                                 "unsupported type in changelist");
-                }
-                if (clen != 6) {
-                        fprintf(stderr, "clen: %ld\n", clen);
-                        rb_p(*chg);
+                event = *chg;
+                unpack_event(&cptr, &clen, &event);
+                if (clen != 6)
                         goto out_list;
-                }
                 event_set(events++, cptr);
         }
         return;
@@ -273,14 +294,23 @@ out_list:
  */
 static void changelist_prepare(struct kevent *events, VALUE changelist)
 {
+        VALUE *cptr;
+        VALUE clen;
+        VALUE event;
+
         switch (TYPE(changelist)) {
         case T_ARRAY:
                 ary2eventlist(events, changelist);
-                break;
+                return;
         case T_STRUCT:
-                if (RSTRUCT_LEN(changelist) != 6)
+                event = changelist;
+                unpack_event(&cptr, &clen, &event);
+                if (clen != 6)
                         rb_raise(rb_eTypeError, "event is not a Kevent struct");
-                event_set(events, RSTRUCT_PTR(changelist));
+                event_set(events, cptr);
+                return;
+        default:
+                rb_bug("changelist_prepare not type filtered by sp_kevent");
         }
 }
 
diff --git a/test/test_kqueue_io.rb b/test/test_kqueue_io.rb
index 904a1cc..076c9f0 100644
--- a/test/test_kqueue_io.rb
+++ b/test/test_kqueue_io.rb
@@ -16,6 +16,12 @@ class TestKqueueIO < Test::Unit::TestCase
     end
   end
 
+  def test_bad_type
+    kq = Kqueue::IO.new
+    @to_close << kq
+    assert_raises(TypeError) { kq.kevent("HI") }
+  end
+
   def test_multi_event
     kq = Kqueue::IO.new
     @to_close << kq