From f809a87f70f0937a87b5d3a83704847daceef4dd Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 20 May 2011 19:50:34 -0700 Subject: Kgio.poll: ensure EINTR never gets raised Retry on a zero timeout if we get interrupted even if the timeout expired. This is also what IO.select does in Ruby itself. --- ext/kgio/poll.c | 6 +++--- 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) -- cgit v1.2.3-24-ge0c7