[macruby-changes] [3254] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Tue Jan 12 16:47:25 PST 2010


Revision: 3254
          http://trac.macosforge.org/projects/ruby/changeset/3254
Author:   ernest.prabhakar at gmail.com
Date:     2010-01-12 16:47:20 -0800 (Tue, 12 Jan 2010)
Log Message:
-----------
Added Dispatch::FileSource and 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	2010-01-12 22:40:35 UTC (rev 3253)
+++ MacRuby/trunk/gcd.c	2010-01-13 00:47:20 UTC (rev 3254)
@@ -80,7 +80,6 @@
     dispatch_source_t source;
     dispatch_source_type_t type; // remove?
     rb_vm_block_t *event_handler;
-    rb_vm_block_t *cancel_handler;// remove?
 } rb_source_t;
 
 #define RSource(val) ((rb_source_t*)val)
@@ -107,6 +106,7 @@
 
 static VALUE cGroup;
 static VALUE cSource;
+static VALUE cFileSource;
 static VALUE cTimer;
 static VALUE cSemaphore;
 
@@ -748,12 +748,6 @@
     return NO;
 }
 
-static inline BOOL
-rb_is_timer_source_type(VALUE num)
-{
-    return (NUM2LONG(num) == SOURCE_TYPE_TIMER) ? YES : NO;
-}
-
 static VALUE
 rb_source_alloc(VALUE klass, SEL sel)
 {
@@ -763,9 +757,50 @@
     return (VALUE)source;
 }
 
-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)
+{
+    assert(sourceptr != NULL);
+    rb_source_t *source = RSource(sourceptr);
+    VALUE param = (VALUE) source;
+    rb_vm_block_t *the_block = source->event_handler;
+    rb_vm_block_eval(the_block, 1, &param);
+}
 
+static VALUE
+rb_source_on_event(VALUE self, SEL sel)
+{
+    rb_source_t *src = RSource(self);
+    rb_vm_block_t *block = given_block();
+    GC_WB(&src->event_handler, block);
+    GC_RETAIN(self);
+    dispatch_set_context(src->source, (void *)self); // retain this?
+    dispatch_source_set_event_handler_f(src->source, rb_source_event_handler);
+    return Qnil;
+}
+
+static VALUE
+rb_source_setup(VALUE self, SEL sel,
+    VALUE type, VALUE handle, VALUE mask, VALUE queue)
+{
+    Check_Queue(queue);
+    rb_source_t *src = RSource(self);    
+    src->type = rb_num2source_type(type);
+    assert(src->type != NULL);
+    uintptr_t c_handle = NUM2UINT(handle);
+    unsigned long c_mask = NUM2LONG(mask);
+    dispatch_queue_t c_queue = RQueue(queue)->queue;
+    src->source = dispatch_source_create(src->type, c_handle, c_mask, c_queue);
+    assert(src->source != NULL);
+
+    if (rb_block_given_p()) {
+        rb_source_on_event(self, 0);
+    } else {
+        rb_raise(rb_eArgError, "No event handler for Dispatch::Source.");
+    }
+    return self;
+}
+
 /* 
  *  call-seq:
  *    Dispatch::Source.new(type, handle, mask, queue) {|src| block}
@@ -779,7 +814,7 @@
  *  
  *     gcdq = Dispatch::Queue.new('doc')
  *     src = Dispatch::Source.new(Dispatch::Source::DATA_ADD, 0, 0, gcdq) do |s|
- *       puts "Fired!"
+ *       puts "Fired with #{s.data}"
  *     end
  *
  *   Unlike with the C API, Dispatch::Source objects start off resumed
@@ -795,48 +830,11 @@
 rb_source_init(VALUE self, SEL sel,
     VALUE type, VALUE handle, VALUE mask, VALUE queue)
 {
-    Check_Queue(queue);
-    rb_source_t *src = RSource(self);    
-    src->type = rb_num2source_type(type);
-    assert(src->type != NULL);
-    uintptr_t c_handle = NUM2UINT(handle);
-    unsigned long c_mask = NUM2LONG(mask);
-    dispatch_queue_t c_queue = RQueue(queue)->queue;
-    src->source = dispatch_source_create(src->type, c_handle, c_mask, c_queue);
-    assert(src->source != NULL);
-
-    if (rb_block_given_p()) {
-        rb_source_on_event(self, 0);
-    } else {
-        rb_raise(rb_eArgError, "No event handler for Dispatch::Source.");
-    }
-
-    rb_dispatch_resume(self, 0); // Does this work okay for timers?
+    rb_source_setup(self, sel, type, handle, mask, queue);
+    rb_dispatch_resume(self, 0);
     return self;
 }
 
-static void
-rb_source_event_handler(void* sourceptr)
-{
-    assert(sourceptr != NULL);
-    rb_source_t *source = RSource(sourceptr);
-    VALUE param = (VALUE) source;
-    rb_vm_block_t *the_block = source->event_handler;
-    rb_vm_block_eval(the_block, 1, &param);
-}
-
-static VALUE
-rb_source_on_event(VALUE self, SEL sel)
-{
-    rb_source_t *src = RSource(self);
-    rb_vm_block_t *block = given_block();
-    GC_WB(&src->event_handler, block);
-    GC_RETAIN(self);
-    dispatch_set_context(src->source, (void *)self); // retain this?
-    dispatch_source_set_event_handler_f(src->source, rb_source_event_handler);
-    return Qnil;
-}
-
 /* 
  *  call-seq:
  *    src.handle => Number
@@ -922,47 +920,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);
-}
-
-/* 
- *  call-seq:
- *    src.on_cancel { |src| block }
- *
- *  This specifies an optional cancellation handler to be submitted exactly once
- *  to the target queue, and only when the source has been cancelled.
- *
- *  This is most commonly used to close File descriptors associated with
- *  Dispatch::Source::WRITE, Dispatch::Source::READ and Dispatch::Source::VNODE
- *
- *     gcdq = Dispatch::Queue.new('doc')
- *     file = File.open("/etc/passwd")
- *     src = Dispatch::Source.new(Dispatch::Source::READ, file, 0, gcdq) { }
- *     src.on_cancel { file.close }
- *     src.cancel!
- *
- */
- 
 static VALUE
-rb_source_on_cancellation(VALUE self, SEL sel)
-{
-    rb_source_t *src = RSource(self);
-    rb_vm_block_t *the_block = rb_vm_current_block();
-    if (the_block == NULL) {
-        rb_raise(rb_eArgError, "on_cancellation() requires a block argument");
-    }
-    GC_WB(&src->cancel_handler, the_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);
@@ -991,13 +949,61 @@
     if (rb_source_finalize_super != NULL) {
         ((void(*)(void *, SEL))rb_source_finalize_super)(rcv, sel);
     }
+}
 
+
+static void
+rb_source_close_handler(void* longptr)
+{
+    long filedes = (long)longptr;
+    close((int)filedes);
 }
 
+/* 
+ *  call-seq:
+ *    Dispatch::FileSource.new(type, handle, mask, queue) 
+ *     {|src| block} => Dispatch::Source
+ *
+ *  Like Dispatch::Source.new, except that it automatically creates
+ *  a cancel handler that will close(2) that file descriptor
+ *  
+ *     gcdq = Dispatch::Queue.new('doc')
+ *     file = File.open("/etc/passwd", r)
+ *     src = Dispatch::Source.new_close_file(Dispatch::Source::READ,
+ *           file.to_i, 0, gcdq) { |s| s.cancel! }
+ *
+ *   The type must be one of:
+ *      - Dispatch::Source::READ
+ *      - Dispatch::Source::WRITE
+ *      - Dispatch::Source::VNODE
+ *
+ *   This is the only way to set the cancel_handler, since in MacRuby
+ *   sources start off resumed. This is preferred to closing the file
+ *   yourself, as the cancel handler is guaranteed to only run once.
+ *
+ *   NOTE: If you do NOT want the file descriptor closed, use Dispatch::Source.
+ *  
+ */
 
+static VALUE
+rb_source_file_init(VALUE self, SEL sel,
+    VALUE type, VALUE handle, VALUE mask, VALUE queue)
+{
+    if (rb_is_file_source_type(type) == NO) {
+        rb_raise(rb_eArgError, "%ld not a file source type", NUM2LONG(type));
+    }
+    rb_source_setup(self, sel, type, handle, mask, queue);
+    rb_source_t *src = RSource(self);            
+    long fildes = NUM2INT(type);
+    dispatch_set_context(src->source, (void*)fildes);
+    dispatch_source_set_cancel_handler_f(src->source, rb_source_close_handler);
+    rb_dispatch_resume(self, 0);
+    return self;
+}
+
 /* 
  *  call-seq:
- *    Dispatch::Timer.new(delay, interval, leeway) =>  Dispatch::Timer
+ *    Dispatch::Timer.new(delay, interval, leeway, queue) =>  Dispatch::Timer
  *
  *  Returns a Source that will submit the event handler block to
  *  the target queue after delay, repeated at interval, within leeway, via
@@ -1007,20 +1013,19 @@
  *  a later time even if the leeway is zero.
  *  
  *     gcdq = Dispatch::Queue.new('doc')
- *     timer = Dispatch::Timer.new(Time.now, 5, 0.1)
+ *     timer = Dispatch::Timer.new(Time.now, 5, 0.1, gcdq)
  *
  */
 
 static VALUE
-rb_timer_init(VALUE self, SEL sel, int argc, VALUE* argv)
+rb_source_timer_init(VALUE self, SEL sel,
+ VALUE delay, VALUE interval, VALUE leeway, VALUE queue)
 {
     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),
+    rb_source_setup(self, sel, INT2FIX(SOURCE_TYPE_TIMER),
 	    INT2FIX(0), INT2FIX(0), queue);
 
     if (NIL_P(leeway)) {
@@ -1035,6 +1040,7 @@
 
     dispatch_source_set_timer(src->source, start_time,
 	    rb_num2nsec(interval), rb_num2nsec(leeway));
+    rb_dispatch_resume(self, 0);
     return self;
 }
 
@@ -1257,7 +1263,6 @@
     
     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_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);
@@ -1266,14 +1271,16 @@
     rb_objc_define_method(cSource, "handle", rb_source_get_handle, 0);
     rb_objc_define_method(cSource, "mask", rb_source_get_mask, 0);
     rb_objc_define_method(cSource, "data", rb_source_get_data, 0);
-    rb_objc_define_method(cSource, "<<", rb_source_merge, 1);
+    rb_objc_define_method(cSource, "<<", rb_source_merge, 1);    
+    rb_source_finalize_super = rb_objc_install_method2((Class)cSource,
+	    "finalize", (IMP)rb_source_finalize);
 
+    cFileSource = rb_define_class_under(mDispatch, "FileSource", cSource);
+    rb_objc_define_method(cFileSource, "initialize", rb_source_file_init, 4);
+    
     cTimer = rb_define_class_under(mDispatch, "Timer", cSource);
-    rb_objc_define_method(cTimer, "initialize", rb_timer_init, -1);
+    rb_objc_define_method(cTimer, "initialize", rb_source_timer_init, 4);
 
-    rb_source_finalize_super = rb_objc_install_method2((Class)cSource,
-	    "finalize", (IMP)rb_source_finalize);
-
     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	2010-01-12 22:40:35 UTC (rev 3253)
+++ MacRuby/trunk/spec/macruby/core/gcd/source_spec.rb	2010-01-13 00:47:20 UTC (rev 3254)
@@ -109,15 +109,6 @@
           @q.sync { }
           @i.should == 42
         end        
-
-        it "runs cancel handler when cancelled" do
-          @i = 0
-          src = Dispatch::Source.new(@type, 0, 0, @q) {|s|  @i = 21}
-          src.on_cancel { @i = 42 }
-          src.cancel!
-          @q.sync { }
-          @i.should == 42
-        end
       end
 
       describe :DATA_OR do
@@ -268,6 +259,13 @@
   end
   
   describe "Dispatch::Timer" do
+    before :each do
+      @q = Dispatch::Queue.new('org.macruby.gcd_spec.sources')
+    end
+    it "returns an instance of Dispatch::Source" do
+      src = Dispatch::Timer.new(nil, 0.1, nil, @q) { }
+      src.should be_kind_of(Dispatch::Source)
+    end
   end
 
 end
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100112/f6a25873/attachment-0001.html>


More information about the macruby-changes mailing list