about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-05-20 19:50:34 -0700
committerEric Wong <normalperson@yhbt.net>2011-05-20 19:52:05 -0700
commitf809a87f70f0937a87b5d3a83704847daceef4dd (patch)
tree0c6d46a274b9de7b2676a13927ff033b4b3580fd
parentab732113e13f1690fd2c1a18d1c66beb7864d847 (diff)
downloadkgio-f809a87f70f0937a87b5d3a83704847daceef4dd.tar.gz
Retry on a zero timeout if we get interrupted
even if the timeout expired.  This is also what
IO.select does in Ruby itself.
-rw-r--r--ext/kgio/poll.c6
-rw-r--r--test/test_poll.rb27
2 files changed, 30 insertions, 3 deletions
diff --git a/ext/kgio/poll.c b/ext/kgio/poll.c
index 2f101d1..89f4623 100644
--- a/ext/kgio/poll.c
+++ b/ext/kgio/poll.c
@@ -40,8 +40,6 @@ static int retryable(struct poll_args *a)
 
         if (a->timeout < 0)
                 return 1;
-        if (a->timeout == 0)
-                return 0;
 
         clock_gettime(hopefully_CLOCK_MONOTONIC, &ts);
 
@@ -53,7 +51,9 @@ static int retryable(struct poll_args *a)
         }
         a->timeout -= ts.tv_sec * 1000;
         a->timeout -= ts.tv_nsec / 1000000;
-        return (a->timeout >= 0);
+        if (a->timeout < 0)
+                a->timeout = 0;
+        return 1;
 }
 
 static int num2timeout(VALUE timeout)
diff --git a/test/test_poll.rb b/test/test_poll.rb
index d99e5aa..32d0a4d 100644
--- a/test/test_poll.rb
+++ b/test/test_poll.rb
@@ -90,4 +90,31 @@ class TestPoll < Test::Unit::TestCase
     ensure
       trap(:USR1, orig)
   end
+
+  def test_poll_signal_torture
+    usr1 = 0
+    empty = 0
+    nr = 100
+    set = { @rd => Kgio::POLLIN }
+    trap(:USR1) { usr1 += 1 }
+    pid = fork do
+      trap(:USR1, "DEFAULT")
+      sleep 0.1
+      ppid = Process.ppid
+      nr.times { Process.kill(:USR1, ppid); sleep 0.05 }
+      @wr.syswrite('.')
+      exit!(0)
+    end
+
+    assert_nothing_raised do
+      empty += 1 until Kgio.poll(set.dup, 100)
+    end
+    _, status = Process.waitpid2(pid)
+    assert status.success?, status.inspect
+    assert usr1 > 0, "usr1: #{usr1}"
+    rescue Object => err
+      p [ :err, err ]
+    ensure
+      trap(:USR1, "DEFAULT")
+  end
 end if Kgio.respond_to?(:poll)