about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-05-05 13:11:53 -0700
committerEric Wong <normalperson@yhbt.net>2011-05-05 13:11:53 -0700
commitc821ebeb851807840f74c4cb4f1a10e691bf222a (patch)
tree858c155749ea65acfb99dd76d0376b85a9413841
parentf589a9ae18216e1220bea8f905f33051e88f1ae7 (diff)
downloadkgio-c821ebeb851807840f74c4cb4f1a10e691bf222a.tar.gz
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.
-rw-r--r--ext/kgio/poll.c8
-rw-r--r--test/test_poll.rb20
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)