summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-01-24 07:55:05 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-01-24 07:55:05 +0000
commitb58fac9a97bc2cb7256b9ae37dfb82a352e6f85e (patch)
treec5bbc6f01381965bd8a21085b56773345b7779bb
parent57752a2503525676e3d21f998cb8bb8357a02242 (diff)
wait readable/writable
* ext/io/wait/wait.c (io_wait_readwrite): [EXPERIMENTAL] allow to wait for multiple modes, readable and writable, at once. the arguments may change in the future. [Feature #12013] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53642 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog6
-rw-r--r--ext/io/wait/wait.c77
-rw-r--r--test/io/wait/test_io_wait.rb12
3 files changed, 92 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 6a51649a7b..50292dfe59 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Sun Jan 24 16:54:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/io/wait/wait.c (io_wait_readwrite): [EXPERIMENTAL] allow to
+ wait for multiple modes, readable and writable, at once. the
+ arguments may change in the future. [Feature #12013]
+
Sat Jan 23 22:30:59 2016 K0mA <mctj1218@gmail.com>
* test/ruby/test_array.rb (test_keep_if): Add test for
diff --git a/ext/io/wait/wait.c b/ext/io/wait/wait.c
index 99435460d4..f7a7508eeb 100644
--- a/ext/io/wait/wait.c
+++ b/ext/io/wait/wait.c
@@ -117,8 +117,6 @@ io_ready_p(VALUE io)
/*
* call-seq:
- * io.wait -> IO, true or nil
- * io.wait(timeout) -> IO, true or nil
* io.wait_readable -> IO, true or nil
* io.wait_readable(timeout) -> IO, true or nil
*
@@ -168,6 +166,79 @@ io_wait_writable(int argc, VALUE *argv, VALUE io)
return Qnil;
}
+static int
+wait_mode_sym(VALUE mode)
+{
+ if (mode == ID2SYM(rb_intern("r"))) {
+ return RB_WAITFD_IN;
+ }
+ if (mode == ID2SYM(rb_intern("read"))) {
+ return RB_WAITFD_IN;
+ }
+ if (mode == ID2SYM(rb_intern("readable"))) {
+ return RB_WAITFD_IN;
+ }
+ if (mode == ID2SYM(rb_intern("w"))) {
+ return RB_WAITFD_OUT;
+ }
+ if (mode == ID2SYM(rb_intern("write"))) {
+ return RB_WAITFD_OUT;
+ }
+ if (mode == ID2SYM(rb_intern("writable"))) {
+ return RB_WAITFD_OUT;
+ }
+ if (mode == ID2SYM(rb_intern("rw"))) {
+ return RB_WAITFD_IN|RB_WAITFD_OUT;
+ }
+ if (mode == ID2SYM(rb_intern("read_write"))) {
+ return RB_WAITFD_IN|RB_WAITFD_OUT;
+ }
+ if (mode == ID2SYM(rb_intern("readable_writable"))) {
+ return RB_WAITFD_IN|RB_WAITFD_OUT;
+ }
+ rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
+ return 0;
+}
+
+/*
+ * call-seq:
+ * io.wait(timeout = nil, mode = :read) -> IO, true or nil
+ *
+ * Waits until IO is readable or writable without blocking and returns
+ * +self+, or +nil+ when times out.
+ * Returns +true+ immediately when buffered data is available.
+ * Optional parameter +mode+ is one of +:read+, +:write+, or
+ * +:read_write+.
+ */
+
+static VALUE
+io_wait_readwrite(int argc, VALUE *argv, VALUE io)
+{
+ rb_io_t *fptr;
+ struct timeval timerec;
+ struct timeval *tv = NULL;
+ int event = 0;
+ int i;
+
+ GetOpenFile(io, fptr);
+ for (i = 0; i < argc; ++i) {
+ if (SYMBOL_P(argv[i])) {
+ event |= wait_mode_sym(argv[i]);
+ }
+ else {
+ *(tv = &timerec) = rb_time_interval(argv[i]);
+ }
+ }
+ /* rb_time_interval() and might_mode() might convert the argument */
+ rb_io_check_closed(fptr);
+ if (!event) event = RB_WAITFD_IN;
+ if ((event & RB_WAITFD_IN) && rb_io_read_pending(fptr))
+ return Qtrue;
+ if (wait_for_single_fd(fptr, event, tv))
+ return io;
+ return Qnil;
+}
+
/*
* IO wait methods
*/
@@ -177,7 +248,7 @@ Init_wait(void)
{
rb_define_method(rb_cIO, "nread", io_nread, 0);
rb_define_method(rb_cIO, "ready?", io_ready_p, 0);
- rb_define_method(rb_cIO, "wait", io_wait_readable, -1);
+ rb_define_method(rb_cIO, "wait", io_wait_readwrite, -1);
rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
}
diff --git a/test/io/wait/test_io_wait.rb b/test/io/wait/test_io_wait.rb
index a19d2a1ea9..7b9edea587 100644
--- a/test/io/wait/test_io_wait.rb
+++ b/test/io/wait/test_io_wait.rb
@@ -134,6 +134,18 @@ class TestIOWait < Test::Unit::TestCase
assert_raise(IOError) { @w.wait_writable }
end
+ def test_wait_readwrite
+ assert_equal @r.wait(0, :write), @r.wait(0, :read_write)
+ end
+
+ def test_wait_readwrite_timeout
+ assert_equal @w, @w.wait(0.01, :read_write)
+ written = fill_pipe
+ assert_nil @w.wait(0.01, :read_write)
+ @r.read(written)
+ assert_equal @w, @w.wait(0.01, :read_write)
+ end
+
private
def fill_pipe