about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-03-10 02:12:46 +0000
committerEric Wong <normalperson@yhbt.net>2011-03-10 02:12:46 +0000
commitaa78296c346c31ca6ee0846fe7b8e6c9dd78d764 (patch)
tree6049c7ccdb4f8c73eb2b792b32bc229878fae55b
parentea00a29e69bcfbcaa82ac24adb9fdfefeb9cde4c (diff)
downloadsleepy_penguin-aa78296c346c31ca6ee0846fe7b8e6c9dd78d764.tar.gz
Just like Inotify#take
-rw-r--r--ext/sleepy_penguin/timerfd.c18
-rw-r--r--test/test_timerfd.rb8
2 files changed, 21 insertions, 5 deletions
diff --git a/ext/sleepy_penguin/timerfd.c b/ext/sleepy_penguin/timerfd.c
index 1089f0b..b8d1c2a 100644
--- a/ext/sleepy_penguin/timerfd.c
+++ b/ext/sleepy_penguin/timerfd.c
@@ -106,21 +106,29 @@ static VALUE tfd_read(void *args)
 
 /*
  * call-seq:
- *        tfd.expirations                -> Integer
+ *        tfd.expirations([nonblock])                -> Integer
  *
  * Returns the number of expirations that have occurred.  This will block
- * if no expirations have occurred at the time of the call.
+ * if no expirations have occurred at the time of the call.  Returns +nil+
+ * if +nonblock+ is passed and is +true+
  */
-static VALUE expirations(VALUE self)
+static VALUE expirations(int argc, VALUE *argv, VALUE self)
 {
         ssize_t r;
         int fd = rb_sp_fileno(self);
         uint64_t buf = (uint64_t)fd;
+        VALUE nonblock;
 
-        blocking_io_prepare(fd);
+        rb_scan_args(argc, argv, "01", &nonblock);
+        if (RTEST(nonblock))
+                rb_sp_set_nonblock(fd);
+        else
+                blocking_io_prepare(fd);
 retry:
         r = (ssize_t)rb_sp_io_region(tfd_read, &buf);
         if (r == -1) {
+                if (errno == EAGAIN && RTEST(nonblock))
+                        return Qnil;
                 if (rb_io_wait_readable(fd))
                         goto retry;
                 rb_sys_fail("read(timerfd)");
@@ -156,7 +164,7 @@ void sleepy_penguin_init_timerfd(void)
 
         rb_define_method(cTimerFD, "settime", settime, 3);
         rb_define_method(cTimerFD, "gettime", gettime, 0);
-        rb_define_method(cTimerFD, "expirations", expirations, 0);
+        rb_define_method(cTimerFD, "expirations", expirations, -1);
         id_for_fd = rb_intern("for_fd");
 }
 #endif /* HAVE_SYS_TIMERFD_H */
diff --git a/test/test_timerfd.rb b/test/test_timerfd.rb
index 1b181da..7e102c4 100644
--- a/test/test_timerfd.rb
+++ b/test/test_timerfd.rb
@@ -57,4 +57,12 @@ class TestTimerFD < Test::Unit::TestCase
     assert_equal 0, interval
     assert_in_delta now + 5, value, 0.01
   end
+
+  def test_expirations_nonblock
+    tfd = TimerFD.new(:MONOTONIC)
+    assert_equal([0, 0], tfd.settime(0, 0, 0.01))
+    assert_nil tfd.expirations(true)
+    sleep 0.01
+    assert_equal 1, tfd.expirations
+  end
 end if defined?(SleepyPenguin::TimerFD)