[macruby-changes] [2039] MacRuby/branches/experimental
source_changes at macosforge.org
source_changes at macosforge.org
Tue Jul 21 11:06:06 PDT 2009
Revision: 2039
http://trac.macosforge.org/projects/ruby/changeset/2039
Author: pthomson at apple.com
Date: 2009-07-21 11:06:06 -0700 (Tue, 21 Jul 2009)
Log Message:
-----------
Implemented Kernel#select and ensured that all the specs pass.
Modified Paths:
--------------
MacRuby/branches/experimental/io.c
Removed Paths:
-------------
MacRuby/branches/experimental/spec/frozen/tags/macruby/core/io/select_tags.txt
Modified: MacRuby/branches/experimental/io.c
===================================================================
--- MacRuby/branches/experimental/io.c 2009-07-21 10:45:32 UTC (rev 2038)
+++ MacRuby/branches/experimental/io.c 2009-07-21 18:06:06 UTC (rev 2039)
@@ -3209,18 +3209,6 @@
return bstr;
}
-// static VALUE
-// select_call(VALUE arg)
-// {
-// rb_notimplement();
-// }
-//
-// static VALUE
-// select_end(VALUE arg)
-// {
-// rb_notimplement();
-// }
-
/*
* call-seq:
* IO.select(read_array
@@ -3231,12 +3219,128 @@
* See <code>Kernel#select</code>.
*/
+// helper method. returns the highest-valued file descriptor encountered.
+static int
+build_fd_set_from_io_array(fd_set* set, VALUE arr)
+{
+ int max_fd = 0;
+ FD_ZERO(set);
+ if (!NIL_P(arr))
+ {
+ if (TYPE(arr) != T_ARRAY)
+ {
+ rb_raise(rb_eTypeError, "Kernel#select expects arrays of IO objects");
+ }
+
+ long n = RARRAY_LEN(arr);
+ long ii;
+ for(ii=0; ii<n; ii++)
+ {
+ VALUE io = RARRAY_AT(arr, ii);
+ io = rb_check_convert_type(io, T_FILE, "IO", "to_io");
+ if (NIL_P(io))
+ {
+ rb_raise(rb_eTypeError, "Kernel#select expects arrays of IO objects");
+ }
+ int fd = ExtractIOStruct(io)->fd;
+ FD_SET(fd, set);
+ max_fd = MAX(fd, max_fd);
+ }
+ }
+ return max_fd;
+}
+
+static void
+build_timeval_from_numeric(struct timeval *tv, VALUE num)
+{
+ tv->tv_sec = 0L;
+ tv->tv_usec = 0L;
+ if(FIXNUM_P(num))
+ {
+ if (FIX2LONG(num) < 0)
+ {
+ rb_raise(rb_eArgError, "select() does not accept negative timeouts.");
+ }
+ tv->tv_sec = FIX2LONG(num);
+ }
+ else if (FIXFLOAT_P(num))
+ {
+ double quantity = RFLOAT_VALUE(num);
+ if (quantity < 0.0)
+ {
+ rb_raise(rb_eArgError, "select() does not accept negative timeouts.");
+ }
+ tv->tv_sec = (long)floor(quantity);
+ tv->tv_usec = (long)(1000 * (quantity - floor(quantity)));
+ }
+ else if (!NIL_P(num))
+ {
+ rb_raise(rb_eTypeError, "timeout parameter must be numeric.");
+ }
+}
+
static VALUE
+extract_ready_descriptors(VALUE arr, fd_set* set)
+{
+ VALUE ready_ios = rb_ary_new();
+ if (NIL_P(arr))
+ {
+ return ready_ios;
+ }
+ long len = RARRAY_LEN(arr);
+ long ii;
+ for (ii=0; ii<len; ii++)
+ {
+ VALUE io = RARRAY_AT(arr, ii);
+ VALUE tmp = rb_check_convert_type(io, T_FILE, "IO", "to_io");
+ if (FD_ISSET(ExtractIOStruct(tmp)->fd, set))
+ {
+ rb_ary_push(ready_ios, io);
+ }
+ }
+ return ready_ios;
+}
+
+static VALUE
rb_f_select(VALUE recv, SEL sel, int argc, VALUE *argv)
{
- rb_notimplement();
+ VALUE read_arr, write_arr, err_arr, timeout_val;
+ VALUE readable_arr, writable_arr, errored_arr;
+ rb_scan_args(argc, argv, "13", &read_arr, &write_arr, &err_arr, &timeout_val);
+ fd_set read_set, write_set, err_set;
+ struct timeval timeout;
+
+ // ndfs has to be 1 + the highest fd we're looking for.
+ int temp = 0;
+ int ndfs = build_fd_set_from_io_array(&read_set, read_arr);
+ temp = build_fd_set_from_io_array(&write_set, write_arr);
+ ndfs = MAX(temp, ndfs);
+ temp = build_fd_set_from_io_array(&err_set, err_arr);
+ ndfs = MAX(temp, ndfs);
+ ndfs++;
+
+
+ // A timeval of 0 needs to be distinguished from a NULL timeval, as a
+ // NULL timeval polls indefinitly while a 0 timeval returns immediately.
+ build_timeval_from_numeric(&timeout, timeout_val);
+ struct timeval *timeval_ptr = (NIL_P(timeout_val) ? NULL : &timeout);
+
+ int ready_count = select(ndfs, &read_set, &write_set, &err_set, timeval_ptr);
+ if(ready_count == -1)
+ {
+ rb_sys_fail("select(2) failed");
+ }
+ else if (ready_count == 0)
+ {
+ return Qnil; // no ready file descriptors? return 0.
+ }
+
+ readable_arr = extract_ready_descriptors(read_arr, &read_set);
+ writable_arr = extract_ready_descriptors(write_arr, &write_set);
+ errored_arr = extract_ready_descriptors(err_arr, &err_set);
+
+ return rb_ary_new3(3, readable_arr, writable_arr, errored_arr);
}
-
// Here be dragons.
static VALUE
rb_io_ctl(VALUE io, VALUE req, VALUE arg, int is_io)
Deleted: MacRuby/branches/experimental/spec/frozen/tags/macruby/core/io/select_tags.txt
===================================================================
--- MacRuby/branches/experimental/spec/frozen/tags/macruby/core/io/select_tags.txt 2009-07-21 10:45:32 UTC (rev 2038)
+++ MacRuby/branches/experimental/spec/frozen/tags/macruby/core/io/select_tags.txt 2009-07-21 18:06:06 UTC (rev 2039)
@@ -1,11 +0,0 @@
-fails:IO.select blocks for duration of timeout if there are no objects ready for I/O
-fails:IO.select returns immediately all objects that are ready for I/O when timeout is 0
-fails:IO.select returns nil after timeout if there are no objects ready for I/O
-fails:IO.select returns supplied objects when they are ready for I/O
-fails:IO.select returns supplied objects correctly even when monitoring the same object in different arrays
-fails:IO.select invokes to_io on supplied objects that are not IO
-fails:IO.select raises TypeError if supplied objects are not IO
-fails:IO.select raises TypeError if the specified timeout value is not Numeric
-fails:IO.select raises TypeError if the first three arguments are not Arrays
-fails:IO.select does not raise errors if the first three arguments are nil
-fails:IO.select does not accept negative timeouts
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090721/a729b7d8/attachment.html>
More information about the macruby-changes
mailing list