Revision: 3152 http://trac.macosforge.org/projects/ruby/changeset/3152 Author: ernest.prabhakar@gmail.com Date: 2009-12-22 16:25:33 -0800 (Tue, 22 Dec 2009) Log Message: ----------- Added new initalizer for Dispatch::Timer Modified Paths: -------------- MacRuby/trunk/gcd.c MacRuby/trunk/spec/macruby/core/gcd/source_spec.rb Modified: MacRuby/trunk/gcd.c =================================================================== --- MacRuby/trunk/gcd.c 2009-12-22 23:07:31 UTC (rev 3151) +++ MacRuby/trunk/gcd.c 2009-12-23 00:25:33 UTC (rev 3152) @@ -13,6 +13,7 @@ #define GCD_BLOCKS_COPY_DVARS 1 #include <dispatch/dispatch.h> +#include <unistd.h> #include "ruby/intern.h" #include "ruby/node.h" #include "ruby/io.h" @@ -105,6 +106,7 @@ static VALUE cGroup; static VALUE cSource; +static VALUE cTimer; static VALUE cSemaphore; static inline rb_vm_block_t * @@ -692,15 +694,44 @@ case SOURCE_TYPE_VNODE: return DISPATCH_SOURCE_TYPE_VNODE; case SOURCE_TYPE_WRITE: return DISPATCH_SOURCE_TYPE_WRITE; default: rb_raise(rb_eArgError, - "Unknown dispatch source type [%d]", value); + "Unknown dispatch source type `%d'", value); } return NULL; } +static inline BOOL +rb_is_file_source_type(VALUE num) +{ + enum SOURCE_TYPE_ENUM value = NUM2LONG(num); + if (value == SOURCE_TYPE_READ || value == SOURCE_TYPE_VNODE + || value == SOURCE_TYPE_WRITE) { + return YES; + } + return NO; +} +static inline BOOL +rb_is_timer_source_type(VALUE num) +{ + return (NUM2LONG(num) == SOURCE_TYPE_TIMER) ? YES : NO; +} + + static VALUE rb_source_on_event(VALUE self, SEL sel); -static void rb_source_event_handler(void* sourceptr); +//static void rb_source_event_handler(void* sourceptr); +static void +rb_source_close_file(void *source) +{ + assert(source != NULL); + uintptr_t handle = dispatch_source_get_handle(RSource(source)->source); + int filedes = (int)handle; + if (close(filedes) != 0) { + rb_raise(rb_eIOError, "Closing descriptor `%d' fails with error: %d", + filedes, errno); + } +} + static VALUE rb_source_alloc(VALUE klass, SEL sel) { @@ -715,20 +746,54 @@ rb_source_init(VALUE self, SEL sel, VALUE type, VALUE handle, VALUE mask, VALUE queue) { - rb_source_t *src = RSource(self); Check_Queue(queue); - + rb_source_t *src = RSource(self); src->type = rb_num2source_type(type); src->source = dispatch_source_create(src->type, NUM2UINT(handle), NUM2LONG(mask), RQueue(queue)->queue); if (rb_block_given_p()) { rb_source_on_event(self, 0); + } else { + rb_raise(rb_eArgError, "No event handler for Dispatch::Source."); } + if (rb_is_file_source_type(type)) { + dispatch_set_context(src->source, (void*)self); // retain this? + dispatch_source_set_cancel_handler_f(src->source, rb_source_close_file); + } + + rb_dispatch_resume(self, 0); // Does this work okay for timers? return self; } +static VALUE +rb_timer_init(VALUE self, SEL sel, int argc, VALUE* argv) +{ + dispatch_time_t start_time; + rb_source_t *src = RSource(self); + VALUE queue = Qnil, interval = Qnil, delay = Qnil, leeway = Qnil; + rb_scan_args(argc, argv, "31", &queue, &delay, &interval, &leeway); + Check_Queue(queue); + + rb_source_init(self, sel, INT2FIX(SOURCE_TYPE_TIMER), + INT2FIX(0), INT2FIX(0), queue); + + if (NIL_P(leeway)) { + leeway = INT2FIX(0); + } + if (NIL_P(delay)) { + start_time = DISPATCH_TIME_NOW; + } + else { + start_time = rb_num2timeout(delay); + } + + dispatch_source_set_timer(src->source, start_time, + rb_num2nsec(interval), rb_num2nsec(leeway)); + return self; +} + static void rb_source_event_handler(void* sourceptr) { @@ -750,26 +815,7 @@ return Qnil; } -static void -rb_source_cancel_handler(void *source) -{ - assert(source != NULL); - rb_vm_block_t *the_block = RSource(source)->cancel_handler; - rb_vm_block_eval(the_block, 0, NULL); -} - static VALUE -rb_source_on_cancellation(VALUE self, SEL sel) -{ - rb_source_t *src = RSource(self); - rb_vm_block_t *block = given_block(); - GC_WB(&src->cancel_handler, block); - dispatch_set_context(src->source, (void*)self); // retain this? - dispatch_source_set_cancel_handler_f(src->source, rb_source_cancel_handler); - return Qnil; -} - -static VALUE rb_source_cancel(VALUE self, SEL sel) { dispatch_source_cancel(RSource(self)->source); @@ -926,19 +972,19 @@ rb_define_const(cSource, "PROC", INT2NUM(SOURCE_TYPE_PROC)); rb_define_const(cSource, "READ", INT2NUM(SOURCE_TYPE_READ)); rb_define_const(cSource, "SIGNAL", INT2NUM(SOURCE_TYPE_SIGNAL)); - rb_define_const(cSource, "TIMER", INT2NUM(SOURCE_TYPE_TIMER)); rb_define_const(cSource, "VNODE", INT2NUM(SOURCE_TYPE_VNODE)); rb_define_const(cSource, "WRITE", INT2NUM(SOURCE_TYPE_WRITE)); rb_objc_define_method(*(VALUE *)cSource, "alloc", rb_source_alloc, 0); rb_objc_define_method(cSource, "initialize", rb_source_init, 4); - rb_objc_define_method(cSource, "on_event", rb_source_on_event, 0); - rb_objc_define_method(cSource, "on_cancel", rb_source_on_cancellation, 0); rb_objc_define_method(cSource, "cancelled?", rb_source_cancelled_p, 0); rb_objc_define_method(cSource, "cancel!", rb_source_cancel, 0); rb_objc_define_method(cSource, "resume!", rb_dispatch_resume, 0); rb_objc_define_method(cSource, "suspend!", rb_dispatch_suspend, 0); rb_objc_define_method(cSource, "suspended?", rb_dispatch_suspended_p, 0); + cTimer = rb_define_class_under(mDispatch, "Timer", cSource); + rb_objc_define_method(cTimer, "initialize", rb_timer_init, -1); + cSemaphore = rb_define_class_under(mDispatch, "Semaphore", rb_cObject); rb_objc_define_method(*(VALUE *)cSemaphore, "alloc", rb_semaphore_alloc, 0); rb_objc_define_method(cSemaphore, "initialize", rb_semaphore_init, 1); Modified: MacRuby/trunk/spec/macruby/core/gcd/source_spec.rb =================================================================== --- MacRuby/trunk/spec/macruby/core/gcd/source_spec.rb 2009-12-22 23:07:31 UTC (rev 3151) +++ MacRuby/trunk/spec/macruby/core/gcd/source_spec.rb 2009-12-23 00:25:33 UTC (rev 3152) @@ -21,8 +21,8 @@ Dispatch::Source.const_defined?(:WRITE).should == true end - it "for timer source" do - Dispatch::Source.const_defined?(:TIMER).should == true + it "NOT for timer source" do + Dispatch::Source.const_defined?(:TIMER).should == false end it "NOT for mach sources" do @@ -36,12 +36,28 @@ @q = Dispatch::Queue.concurrent end - it "creates a custom Source" do - Dispatch::Source.new(Dispatch::Source::DATA_ADD, 0, 0, @q).should + it "can create a custom Source" do + Dispatch::Source.new(Dispatch::Source::DATA_ADD, 0, 0, @q) {}.should be_kind_of(Dispatch::Source) - Dispatch::Source.new(Dispatch::Source::DATA_OR, 0, 0, @q).should + Dispatch::Source.new(Dispatch::Source::DATA_OR, 0, 0, @q) {}.should be_kind_of(Dispatch::Source) end + + it "can create a process Source" do + Dispatch::Source.new(Dispatch::Source::PROC, 0, 0, @q) {}.should + be_kind_of(Dispatch::Source) + Dispatch::Source.new(Dispatch::Source::SIGNAL, 0, 0, @q) {}.should + be_kind_of(Dispatch::Source) + end + + it "can create a file Source" do + Dispatch::Source.new(Dispatch::Source::READ, 0, 0, @q) {}.should + be_kind_of(Dispatch::Source) + Dispatch::Source.new(Dispatch::Source::VNODE, 0, 0, @q) {}.should + be_kind_of(Dispatch::Source) + Dispatch::Source.new(Dispatch::Source::WRITE, 0, 0, @q) {}.should + be_kind_of(Dispatch::Source) + end end