From c821ebeb851807840f74c4cb4f1a10e691bf222a Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 5 May 2011 13:11:53 -0700 Subject: poll: deal with pollset changes on EINTR This allows callers to modify the pollset, interrupt the polling thread, and then poll with the modified pollset. This is also important for dealing with closed IO objects that may have been invalidated due to GC, too. --- ext/kgio/poll.c | 8 +++++--- test/test_poll.rb | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ext/kgio/poll.c b/ext/kgio/poll.c index 614d939..2f101d1 100644 --- a/ext/kgio/poll.c +++ b/ext/kgio/poll.c @@ -100,6 +100,7 @@ static int io_to_pollfd_i(VALUE key, VALUE value, VALUE args) static void hash2pollfds(struct poll_args *a) { + a->nfds = 0; a->fds = xmalloc(sizeof(struct pollfd) * RHASH_SIZE(a->ios)); a->fd_to_io = st_init_numtable(); rb_hash_foreach(a->ios, io_to_pollfd_i, (VALUE)a); @@ -140,14 +141,16 @@ static VALUE do_poll(VALUE args) int nr; Check_Type(a->ios, T_HASH); - hash2pollfds(a); retry: + hash2pollfds(a); nr = (int)rb_thread_blocking_region(nogvl_poll, a, RUBY_UBF_IO, NULL); if (nr < 0) { if (interrupted()) { - if (retryable(a)) + if (retryable(a)) { + poll_free(args); goto retry; + } return Qnil; } rb_sys_fail("poll"); @@ -196,7 +199,6 @@ static VALUE s_poll(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "11", &a.ios, &timeout); a.timeout = num2timeout(timeout); - a.nfds = 0; a.fds = NULL; a.fd_to_io = NULL; diff --git a/test/test_poll.rb b/test/test_poll.rb index 1c92223..d99e5aa 100644 --- a/test/test_poll.rb +++ b/test/test_poll.rb @@ -70,4 +70,24 @@ class TestPoll < Test::Unit::TestCase ensure trap(:USR1, orig) end + + def test_poll_EINTR_changed + ok = false + orig = trap(:USR1) { ok = true } + pollset = { @rd => Kgio::POLLIN } + thr = Thread.new do + sleep 0.100 + pollset[@wr] = Kgio::POLLOUT + Process.kill(:USR1, $$) + end + t0 = Time.now + res = Kgio.poll(pollset, 1000) + diff = Time.now - t0 + thr.join + assert_equal({@wr => Kgio::POLLOUT}, res) + assert diff < 1.0, "diff=#{diff}" + assert ok + ensure + trap(:USR1, orig) + end end if Kgio.respond_to?(:poll) -- cgit v1.2.3-24-ge0c7