[macruby-changes] [3198] MacRuby/trunk/gcd.c

source_changes at macosforge.org source_changes at macosforge.org
Wed Jan 6 16:31:58 PST 2010


Revision: 3198
          http://trac.macosforge.org/projects/ruby/changeset/3198
Author:   ernest.prabhakar at gmail.com
Date:     2010-01-06 16:31:58 -0800 (Wed, 06 Jan 2010)
Log Message:
-----------
Completed Dispatch::Source API and Documentation, though neither work/are tested :-/

Modified Paths:
--------------
    MacRuby/trunk/gcd.c

Modified: MacRuby/trunk/gcd.c
===================================================================
--- MacRuby/trunk/gcd.c	2010-01-06 23:35:23 UTC (rev 3197)
+++ MacRuby/trunk/gcd.c	2010-01-07 00:31:58 UTC (rev 3198)
@@ -768,17 +768,27 @@
 
 /* 
  *  call-seq:
- *    Dispatch::Source.new(type, handle, mask, queue) =>  Dispatch::Source
+ *    Dispatch::Source.new(type, handle, mask, queue) {|src| block}
+ *     => Dispatch::Source
  *
  *  Returns a Source used to monitor a variety of system objects and events
  *  including file descriptors, processes, virtual filesystem nodes, signal
  *  delivery and timers.
  *  When a state change occurs, the dispatch source will submit its event
- *  handler block to its target queue.
+ *  handler block to its target queue, with the source as a parameter.
  *  
  *     gcdq = Dispatch::Queue.new('doc')
- *     src = Dispatch::Source.new(Dispatch::Source::DATA_ADD, 1, 2, gcdq)
+ *     src = Dispatch::Source.new(Dispatch::Source::DATA_ADD, 0, 0, gcdq) do |s|
+ *       puts "Fired!"
+ *     end
  *
+ *   Unlike with the C API, Dispatch::Source objects start off resumed
+ *   (since the event handler has already been set).
+ *   
+ *     src.suspended? #=? false
+ *     src.merge(0)
+ *     gcdq.sync { } #=> Fired!
+ *  
  */
 
 static VALUE
@@ -824,14 +834,132 @@
     return Qnil;
 }
 
+/* 
+ *  call-seq:
+ *    src.handle => Number
+ *
+ *  Returns the underlying handle to the dispatch source (i.e. file descriptor,
+ *  process identifer, etc.). For Ruby, this must be representable as a Number.
+ *  
+ *     gcdq = Dispatch::Queue.new('doc')
+ *     src = Dispatch::Source.new(Dispatch::Source::DATA_ADD, 0, 0, gcdq) { }
+ *     puts src.handle #=> 0
+ */
+
 static VALUE
+rb_source_get_handle(VALUE self, SEL sel)
+{
+    return LONG2NUM(dispatch_source_get_handle(RSource(self)->source));
+}
+
+/* 
+ *  call-seq:
+ *    src.mask => Number
+ *
+ *  Returns a Number representing the mask argument, corresponding to the flags
+ *  set when the source was created.
+ *  
+ *     gcdq = Dispatch::Queue.new('doc')
+ *     src = Dispatch::Source.new(Dispatch::Source::DATA_ADD, 0, 0, gcdq) { }
+ *     puts src.mask #=> 0
+ */
+
+static VALUE
+rb_source_get_mask(VALUE self, SEL sel)
+{
+    return INT2NUM(dispatch_source_get_mask(RSource(self)->source));
+}
+
+/* 
+ *  call-seq:
+ *    src.data => Number
+ *
+ *  Returns a Number containing currently pending data for the dispatch source.
+ *  This function should only be called from within the source's event handler.
+ *  The result of calling this function from any other context is undefined.
+ *  
+ *     gcdq = Dispatch::Queue.new('doc')
+ *     src = Dispatch::Source.new(Dispatch::Source::DATA_ADD, 0, 0, gcdq) do |s|
+ *       puts s.data
+ *     end
+ *     src.merge(1)
+ *     gcdq.sync { } #=> 1
+ */
+
+static VALUE
+rb_source_get_data(VALUE self, SEL sel)
+{
+    return LONG2NUM(dispatch_source_get_mask(RSource(self)->source));
+}
+
+/* 
+ *  call-seq:
+ *    src.merge(number)
+ *
+ *  Intended only for use with the Dispatch::Source::DATA_ADD and
+ *  Dispatch::Source::DATA_OR source types, calling this function will
+ *  atomically ADD or logical OR the count into the source's data, and 
+ * trigger delivery of the source's event handler.
+ *  
+ *     gcdq = Dispatch::Queue.new('doc')
+ *     @sum = 0
+ *     src = Dispatch::Source.new(Dispatch::Source::DATA_ADD, 0, 0, gcdq) do |s|
+ *       @sum += s.data # safe since always serialized
+ *     end
+ *     src.merge(1)
+ *     src.merge(3)
+ *     gcdq.sync { }
+ *     puts @sum #=> 4
+ */
+
+static VALUE
 rb_source_merge(VALUE self, SEL sel, VALUE data)
 {
     dispatch_source_merge_data(RSource(self)->source, NUM2INT(data));
     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);
@@ -917,7 +1045,6 @@
     return (VALUE)s;
 }
 
-
 /* 
  *  call-seq:
  *    Dispatch::Semaphore.new(count) =>  Dispatch::Semaphore
@@ -1113,11 +1240,15 @@
     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_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);
+    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, "merge", rb_source_merge, 1);
 
     cTimer = rb_define_class_under(mDispatch, "Timer", cSource);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100106/cc63e548/attachment-0001.html>


More information about the macruby-changes mailing list