about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--ext/sleepy_penguin/eventfd.c85
-rw-r--r--ext/sleepy_penguin/sleepy_penguin.h2
-rw-r--r--test/test_eventfd.rb16
3 files changed, 34 insertions, 69 deletions
diff --git a/ext/sleepy_penguin/eventfd.c b/ext/sleepy_penguin/eventfd.c
index 06663a8..74c3f00 100644
--- a/ext/sleepy_penguin/eventfd.c
+++ b/ext/sleepy_penguin/eventfd.c
@@ -66,35 +66,42 @@ static VALUE efd_read(void *_args)
 
 /*
  * call-seq:
- *        efd.incr(integer_value)        -> nil
+ *        efd.incr(integer_value[, nonblock ])        -> true or nil
  *
  * Increments the internal counter by +integer_value+ which is an unsigned
- * Integer value.  This will block if the internal counter will overflow
- * the value of EventFD::MAX
+ * Integer value.
+ *
+ * If +nonblock+ is specified and true, this will return +nil+ if the
+ * internal counter will overflow the value of EventFD::MAX.
+ * Otherwise it will block until the counter may be incremented without
+ * overflowing.
  */
-static VALUE incr(VALUE self, VALUE value)
+static VALUE incr(int argc, VALUE *argv, VALUE self)
 {
         struct efd_args x;
         ssize_t w;
+        VALUE value, nonblock;
 
+        rb_scan_args(argc, argv, "11", &value, &nonblock);
         x.fd = rb_sp_fileno(self);
-        blocking_io_prepare(x.fd);
+        RTEST(nonblock) ? rb_sp_set_nonblock(x.fd) : blocking_io_prepare(x.fd);
         x.val = (uint64_t)NUM2ULL(value);
-
 retry:
         w = (ssize_t)rb_sp_io_region(efd_write, &x);
         if (w == -1) {
+                if (errno == EAGAIN && RTEST(nonblock))
+                        return Qfalse;
                 if (rb_io_wait_writable(x.fd))
                         goto retry;
                 rb_sys_fail("write(eventfd)");
         }
 
-        return Qnil;
+        return Qtrue;
 }
 
 /*
  * call-seq:
- *        efd.value        -> Integer
+ *        efd.value([nonblock])        -> Integer or nil
  *
  * If not created as a semaphore, returns the current value and resets
  * the counter to zero.
@@ -103,19 +110,23 @@ retry:
  * and returns +1+.
  *
  * If the counter is zero at the time of the call, this will block until
- * the counter becomes non-zero.
+ * the counter becomes non-zero unless +nonblock+ is +true+, in which
+ * case it returns +nil+.
  */
-static VALUE getvalue(VALUE self)
+static VALUE getvalue(int argc, VALUE argv, VALUE self)
 {
         struct efd_args x;
         ssize_t w;
+        VALUE nonblock;
 
+        rb_scan_args(argc, argv, "01", &nonblock);
         x.fd = rb_sp_fileno(self);
-        blocking_io_prepare(x.fd);
-
+        RTEST(nonblock) ? rb_sp_set_nonblock(x.fd) : blocking_io_prepare(x.fd);
 retry:
         w = (ssize_t)rb_sp_io_region(efd_read, &x);
         if (w == -1) {
+                if (errno == EAGAIN && RTEST(nonblock))
+                        return Qnil;
                 if (rb_io_wait_readable(x.fd))
                         goto retry;
                 rb_sys_fail("read(eventfd)");
@@ -124,50 +135,6 @@ retry:
         return ULL2NUM(x.val);
 }
 
-/*
- * call-seq:
- *        efd.value_nonblock        -> Integer
- *
- * Exactly like EventFD#value, but forces the EventFD object
- * into non-blocking mode if it is not already and raises Errno::EAGAIN
- * if it is not ready for reading.
- */
-static VALUE value_nonblock(VALUE self)
-{
-        int fd = rb_sp_fileno(self);
-        uint64_t val;
-        ssize_t r;
-
-        rb_sp_set_nonblock(fd);
-        r = read(fd, &val, sizeof(uint64_t));
-        if (r == -1)
-                rb_sys_fail("read(eventfd)");
-
-        return ULL2NUM(val);
-}
-
-/*
- * call-seq:
- *        efd.incr_nonblock(integer_value)        -> nil
- *
- * Exactly like EventFD#incr, but forces the EventFD object
- * into non-blocking mode if it is not already and raises Errno::EAGAIN
- * if it may overflow.
- */
-static VALUE incr_nonblock(VALUE self, VALUE value)
-{
-        int fd = rb_sp_fileno(self);
-        uint64_t val = (uint64_t)NUM2ULL(value);
-        ssize_t w;
-
-        rb_sp_set_nonblock(fd);
-        w = write(fd, &val, sizeof(uint64_t));
-        if (w == -1)
-                rb_sys_fail("write(eventfd)");
-
-        return Qnil;
-}
-
 void sleepy_penguin_init_eventfd(void)
 {
         VALUE mSleepyPenguin, cEventFD;
@@ -201,10 +168,8 @@ void sleepy_penguin_init_eventfd(void)
 #ifdef EFD_SEMAPHORE
         NODOC_CONST(cEventFD, "SEMAPHORE", INT2NUM(EFD_SEMAPHORE));
 #endif
-        rb_define_method(cEventFD, "value", getvalue, 0);
-        rb_define_method(cEventFD, "incr", incr, 1);
-        rb_define_method(cEventFD, "value_nonblock", value_nonblock, 0);
-        rb_define_method(cEventFD, "incr_nonblock", incr_nonblock, 1);
+        rb_define_method(cEventFD, "value", getvalue, -1);
+        rb_define_method(cEventFD, "incr", incr, -1);
         id_for_fd = rb_intern("for_fd");
 }
 #endif /* HAVE_SYS_EVENTFD_H */
diff --git a/ext/sleepy_penguin/sleepy_penguin.h b/ext/sleepy_penguin/sleepy_penguin.h
index 9c2f701..577b7c0 100644
--- a/ext/sleepy_penguin/sleepy_penguin.h
+++ b/ext/sleepy_penguin/sleepy_penguin.h
@@ -23,7 +23,7 @@ static inline VALUE rb_sp_io_region(rb_blocking_function_t *func, void *data)
 {
         return rb_thread_blocking_region(func, data, RUBY_UBF_IO, 0);
 }
-#  define blocking_io_prepare(fd) for(;0;)
+#  define blocking_io_prepare(fd) ((void)(fd))
 #else
 typedef VALUE rb_blocking_function_t(void *);
 VALUE rb_sp_io_region(rb_blocking_function_t *func, void *data);
diff --git a/test/test_eventfd.rb b/test/test_eventfd.rb
index 05b8d01..84ee307 100644
--- a/test/test_eventfd.rb
+++ b/test/test_eventfd.rb
@@ -45,22 +45,22 @@ class TestEventFD < Test::Unit::TestCase
 
   def test_incr_value
     efd = EventFD.new(0)
-    assert_nil efd.incr(1)
+    assert_equal true, efd.incr(1)
     assert_equal 1, efd.value
 
-    assert_raises(Errno::EAGAIN) { efd.value_nonblock }
-    assert_nil efd.incr(9)
-    assert_equal 9, efd.value_nonblock
+    assert_nil efd.value(true)
+    assert_equal true, efd.incr(9)
+    assert_equal 9, efd.value(true)
 
-    assert_nil efd.incr(0xfffffffffffffffe)
-    assert_raises(Errno::EAGAIN) { efd.incr_nonblock 1 }
+    assert_equal true, efd.incr(0xfffffffffffffffe)
+    assert_equal false, efd.incr(1, true)
   end
 
   def test_incr_value_semaphore
     efd = EventFD.new(6, :SEMAPHORE)
     6.times { assert_equal 1, efd.value }
-    assert_raises(Errno::EAGAIN) { efd.value_nonblock }
-    assert_nothing_raised { efd.incr(1) }
+    assert_nil efd.value(true)
+    assert_equal true, efd.incr(1)
     assert_equal 1, efd.value
   end
 end if defined?(SleepyPenguin::EventFD)