diff options
author | Eric Wong <normalperson@yhbt.net> | 2011-05-05 13:11:53 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2011-05-05 13:11:53 -0700 |
commit | c821ebeb851807840f74c4cb4f1a10e691bf222a (patch) | |
tree | 858c155749ea65acfb99dd76d0376b85a9413841 | |
parent | f589a9ae18216e1220bea8f905f33051e88f1ae7 (diff) | |
download | kgio-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.c | 8 | ||||
-rw-r--r-- | 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) |