Beispiel #1
0
void
rb_define_object_special_methods(VALUE klass)
{
    RCLASS_SET_VERSION(*(VALUE *)klass,
	    (RCLASS_VERSION(*(VALUE *)klass) | RCLASS_HAS_ROBJECT_ALLOC));

    rb_objc_define_method(*(VALUE *)klass, "new",
	    rb_class_new_instance_imp, -1);
    rb_objc_define_method(klass, "dup", rb_obj_dup, 0);
    rb_objc_define_private_method(klass, "initialize", rb_objc_init, -1);
    rb_objc_define_private_method(klass, "initialize_copy",
	    rb_obj_init_copy, 1);
    rb_objc_define_method(klass, "hash", rb_obj_id, 0);

    // To make sure singleton classes will be filtered.
    rb_objc_define_method(*(VALUE *)klass, "superclass", rb_obj_superclass, 0);
    rb_objc_define_method(klass, "class", rb_obj_class, 0);

    rb_objc_install_method(*(Class *)klass, selAllocWithZone,
	    (IMP)rb_obj_imp_allocWithZone);
    rb_objc_install_method((Class)klass, selIsEqual,
	    (IMP)rb_obj_imp_isEqual);
    rb_objc_install_method((Class)klass, selInit, (IMP)rb_obj_imp_init);
    rb_objc_install_method((Class)klass, selDescription,
	    (IMP)rb_obj_imp_description);

    // Create -copyWithZone:, since the method doesn't exist yet we need to
    // find the type encoding somewhere, here we check Symbol since it's
    // created very early. 
    Method m = class_getInstanceMethod((Class)rb_cSymbol, selCopyWithZone);
    assert(m != NULL);
    class_replaceMethod((Class)klass, selCopyWithZone, 
	    (IMP)rb_obj_imp_copyWithZone, method_getTypeEncoding(m));
}
Beispiel #2
0
void SwizzInstanceMethod(Class origClass, Class replaceClass, SEL origSel, SEL replaceSel)
{
    Method origMethod = class_getInstanceMethod(origClass, origSel);
    Method newMethod = class_getInstanceMethod(replaceClass, replaceSel);
    if(class_addMethod(origClass, origSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
        class_replaceMethod(origClass, replaceSel, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    else
        method_exchangeImplementations(origMethod, newMethod);
}
Beispiel #3
0
void
Init_Dispatch(void)
{
    high_priority_id = rb_intern("high");
    low_priority_id = rb_intern("low");
    default_priority_id = rb_intern("default");

/*
 *  Grand Central Dispatch (GCD) is a novel approach to multicore computing
 *  first release in Mac OS X version 10.6 Snow Leopard, and available as
 *  open source via the libdispatch project. GCD shifts the
 *  responsibility for managing threads and their execution from
 *  applications onto the operating system. This allows programmers to easily
 *  refactor their programs into small chunks of independent work, which GCD
 *  then schedules onto per-process thread pools.  Because GCD knows the load
 *  across the entire system, it ensures the resulting programs perform
 *  optimally on a wide range of hardware.
 *
 *  The Dispatch module allows Ruby blocks to be scheduled for asynchronous and
 *  concurrent execution, either explicitly or in response to
 *  various kinds of events. It provides a convenient high-level interface
 *  to the underlying C API via objects for the four primary abstractions.
 *
 *  Dispatch::Queue is the basic units of organization of blocks.
 *  Several queues are created by default, and applications may create
 *  additional queues for their own use.
 *
 *  Dispatch::Group allows applications to track the progress of blocks
 *  submitted to queues and take action when the blocks complete.
 * 
 *  Dispatch::Source monitors and coalesces low-level system events so that they
 *  can be responded to asychronously via simple event handlers.
 *
 *  Dispatch::Semaphore synchronizes threads via a combination of
 *  waiting and signalling.
 *
 *  For more information, see the dispatch(3)[http://developer.apple.com/mac/library/DOCUMENTATION/Darwin/Reference/ManPages/man3/dispatch.3.html] man page.  
 */
    mDispatch = rb_define_module("Dispatch");

    cObject = rb_define_class_under(mDispatch, "Object", rb_cObject);
    rb_objc_define_method(cObject, "resume!", rb_dispatch_resume, 0);
    rb_objc_define_method(cObject, "suspend!", rb_dispatch_suspend, 0);
    rb_objc_define_method(cObject, "suspended?", rb_dispatch_suspended_p, 0);

    // This API allows Ruby code to pass the internal dispatch_queue_t object
    // to C/Objective-C APIs.
    class_replaceMethod((Class)cObject, sel_registerName("dispatch_object"),
	    (IMP)dispatch_object_imp, "^v@:");

/*
 * A Dispatch::Queue is the fundamental mechanism for scheduling blocks for
 * execution, either synchronously or asychronously.
 *
 * All blocks submitted to dispatch queues begin executing in the order
 * they were received. The system-defined concurrent queues can execute
 * multiple blocks in parallel, depending on the number of idle threads
 * in the thread pool. Serial queues (the main and user-created queues)
 * wait for the prior block to complete before dequeuing and executing
 * the next block.
 *
 * Queues are not bound to any specific thread of execution and blocks
 * submitted to independent queues may execute concurrently.
 */ 
 
    cQueue = rb_define_class_under(mDispatch, "Queue", cObject);    
    rb_objc_define_method(*(VALUE *)cQueue, "alloc", rb_queue_alloc, 0);
    rb_objc_define_method(*(VALUE *)cQueue, "concurrent",
	    rb_queue_get_concurrent, -1);
    rb_objc_define_method(*(VALUE *)cQueue, "current", rb_queue_get_current, 0);
    rb_objc_define_method(*(VALUE *)cQueue, "main", rb_queue_get_main, 0);
    rb_objc_define_method(cQueue, "initialize", rb_queue_init, 1);
    rb_objc_define_method(cQueue, "initialize", rb_raise_init, 0);
    rb_objc_define_method(cQueue, "apply", rb_queue_apply, 1);
    rb_objc_define_method(cQueue, "async", rb_queue_dispatch_async, -1);
    rb_objc_define_method(cQueue, "sync", rb_queue_dispatch_sync, 0);
    rb_objc_define_method(cQueue, "after", rb_queue_dispatch_after, 1);
    rb_objc_define_method(cQueue, "label", rb_queue_label, 0); // deprecated
    rb_objc_define_method(cQueue, "to_s", rb_queue_label, 0);
    
    rb_queue_finalize_super = rb_objc_install_method2((Class)cQueue,
	    "finalize", (IMP)rb_queue_finalize);

    qHighPriority = rb_queue_from_dispatch(dispatch_get_global_queue(
		DISPATCH_QUEUE_PRIORITY_HIGH, 0), true);
    qDefaultPriority = rb_queue_from_dispatch(dispatch_get_global_queue(
		DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), true);
    qLowPriority = rb_queue_from_dispatch(dispatch_get_global_queue(
		DISPATCH_QUEUE_PRIORITY_LOW, 0), true);
    
    qMain = rb_queue_from_dispatch(dispatch_get_main_queue(), true);
    rb_objc_define_method(rb_singleton_class(qMain), "run", rb_main_queue_run,
	    0);
    
/*
 * Dispatch::Group is used to aggregate multiple blocks 
 * that have been submitted asynchronously to different queues.
 * This lets you ensure they have all completed before beginning
 * or submitting additional work.
 */ 
    cGroup = rb_define_class_under(mDispatch, "Group", cObject);
    rb_objc_define_method(*(VALUE *)cGroup, "alloc", rb_group_alloc, 0);
    rb_objc_define_method(cGroup, "initialize", rb_group_init, 0);
    rb_objc_define_method(cGroup, "notify", rb_group_notify, 1);
    rb_objc_define_method(cGroup, "on_completion", rb_group_notify, 1); // deprecated
    rb_objc_define_method(cGroup, "wait", rb_group_wait, -1);
    
    rb_group_finalize_super = rb_objc_install_method2((Class)cGroup,
	    "finalize", (IMP)rb_group_finalize);

/*
 *  Dispatch::Source monitors a variety of system objects and events including
 *  file descriptors, processes, virtual filesystem nodes, signals and timers.
 *
 *  When a state change occurs, the dispatch source will submit its event
 *  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, 0, 0, gcdq) do |s|
 *       puts "Fired with #{s.data}"
 *     end
 *
 *  Unlike GCD's C API, Dispatch::Source objects start off resumed
 *  (since the event handler -et al- have already been set).
 *   
 *     src.suspended? #=? false
 *     src.merge(0)
 *     gcdq.sync { } #=> Fired!
 */
    cSource = rb_define_class_under(mDispatch, "Source", cObject);
    rb_define_const(cSource, "DATA_ADD", INT2NUM(SOURCE_TYPE_DATA_ADD));
    rb_define_const(cSource, "DATA_OR", INT2NUM(SOURCE_TYPE_DATA_OR));
    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, "VNODE", INT2NUM(SOURCE_TYPE_VNODE));
    rb_define_const(cSource, "WRITE", INT2NUM(SOURCE_TYPE_WRITE));
    
    rb_define_const(cSource, "PROC_EXIT", INT2NUM(DISPATCH_PROC_EXIT));
    rb_define_const(cSource, "PROC_FORK", INT2NUM(DISPATCH_PROC_FORK));
    rb_define_const(cSource, "PROC_EXEC", INT2NUM(DISPATCH_PROC_EXEC));
    rb_define_const(cSource, "PROC_SIGNAL", INT2NUM(DISPATCH_PROC_SIGNAL));

    rb_define_const(cSource, "VNODE_DELETE", INT2NUM(DISPATCH_VNODE_DELETE));
    rb_define_const(cSource, "VNODE_WRITE", INT2NUM(DISPATCH_VNODE_WRITE));
    rb_define_const(cSource, "VNODE_EXTEND", INT2NUM(DISPATCH_VNODE_EXTEND));
    rb_define_const(cSource, "VNODE_ATTRIB", INT2NUM(DISPATCH_VNODE_ATTRIB));
    rb_define_const(cSource, "VNODE_LINK", INT2NUM(DISPATCH_VNODE_LINK));
    rb_define_const(cSource, "VNODE_RENAME", INT2NUM(DISPATCH_VNODE_RENAME));
    rb_define_const(cSource, "VNODE_REVOKE", INT2NUM(DISPATCH_VNODE_REVOKE));

    rb_objc_define_method(*(VALUE *)cSource, "alloc", rb_source_alloc, 0);
    rb_objc_define_method(*(VALUE *)cSource, "timer", rb_source_timer, 4);
    rb_objc_define_method(cSource, "initialize", rb_source_init, 4);
    rb_objc_define_method(cSource, "initialize", rb_raise_init, 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, "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_source_finalize_super = rb_objc_install_method2((Class)cSource,
	    "finalize", (IMP)rb_source_finalize);

/*
 * Dispatch::Semaphore provides an efficient mechanism to synchronizes threads
 * via a combination of waiting and signalling.
 * This is especially useful for controlling access to limited resources.
 */
    cSemaphore = rb_define_class_under(mDispatch, "Semaphore", cObject);
    rb_objc_define_method(*(VALUE *)cSemaphore, "alloc", rb_semaphore_alloc, 0);
    rb_objc_define_method(cSemaphore, "initialize", rb_semaphore_init, 1);
    rb_objc_define_method(cSemaphore, "initialize", rb_raise_init, 0);
    rb_objc_define_method(cSemaphore, "wait", rb_semaphore_wait, -1);
    rb_objc_define_method(cSemaphore, "signal", rb_semaphore_signal, 0);

    rb_semaphore_finalize_super = rb_objc_install_method2((Class)cSemaphore,
	    "finalize", (IMP)rb_semaphore_finalize);

/*
 * Constants for use with
 * dispatch_time(3)[http://developer.apple.com/Mac/library/documentation/Darwin/Reference/ManPages/man3/dispatch_time.3.html]
 */

    rb_define_const(mDispatch, "TIME_NOW", ULL2NUM(DISPATCH_TIME_NOW));
    rb_define_const(mDispatch, "TIME_FOREVER", ULL2NUM(DISPATCH_TIME_FOREVER));
    
/* Constants for future reference */
    selClose = sel_registerName("close");
    assert(selClose != NULL);
}