diff options
author | Eric Wong <normalperson@yhbt.net> | 2011-05-20 19:50:34 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2011-05-20 19:52:05 -0700 |
commit | f809a87f70f0937a87b5d3a83704847daceef4dd (patch) | |
tree | 0c6d46a274b9de7b2676a13927ff033b4b3580fd | |
parent | ab732113e13f1690fd2c1a18d1c66beb7864d847 (diff) | |
download | kgio-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.c | 6 | ||||
-rw-r--r-- | test/test_poll.rb | 27 |
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) |