542 various practitioners around the world. In this model, your method or
543 function takes a callback argument and returns immediately after enqueuing a
544 task to run on one of the threads in the Node.js worker thread pool. That
545 task consists of a C function to be run on the worker thread, which may not
546 use any V8 (or v8+) state, and a function to be run in the main event loop
547 thread when that task has completed. The latter function is normally
548 expected to invoke the caller's original callback. In v8+, this takes the
549 following form:
550
551 void *
552 async_worker(void *cop, void *ctxp)
553 {
554 my_object_t *op = cop;
555 my_context_t *cp = ctxp;
556 my_result_t *rp = ...;
557
558 /*
559 * In thread pool context -- do not call any of the
560 * following functions:
561 * v8plus_obj_hold()
562 * v8plus_obj_rele()
563 * v8plus_jsfunc_hold()
564 * v8plus_jsfunc_rele()
565 * v8plus_call()
566 * v8plus_method_call_direct()
567 * v8plus_defer()
568 *
569 * If you touch anything inside op, you may need locking to
570 * protect against functions called in the main thread.
571 */
572 ...
573
574 return (rp);
575 }
576
577 void
578 async_completion(void *cop, void *ctxp, void *resp)
579 {
580 my_object_t *op = cop;
581 my_context_t *cp = ctxp;
582 my_result_t *rp = resp;
583 nvlist_t *cbap;
584 nvlist_t *cbrp;
585
671 nvlist_free(eap);
672 nvlist_free(erp);
673 }
674
675 This example will generate an event named "my_event" and propagate it to
676 listeners registered with the `MyObjectWrapper` instance. If additional
677 arguments are associated with the event, they may be added to `eap` and will
678 also be passed along to listeners as arguments to their callbacks.
679
680 ### void v8plus_obj_hold(const void *op)
681
682 Places a hold on the V8 representation of the specified C object. This is
683 rarely necessary; `v8plus_defer()` performs this action for you, but other
684 asynchronous mechanisms may require it. If you are returning from a method
685 call but have stashed a reference to the object somewhere and are not
686 calling `v8plus_defer()`, you must call this first. Holds and releases must
687 be balanced. Use of the object within a thread after releasing is a bug.
688
689 ### void v8plus_obj_rele(const void *op)
690
691 Releases a hold placed by `v8plus_obj_hold()`.
692
693 ### void v8plus_jsfunc_hold(v8plus_jsfunc_t f)
694
695 Places a hold on the V8 representation of the specified JavaScript function.
696 This is required when returning from a C function that has stashed a
697 reference to the function, typically to use it asynchronously as a callback.
698 All holds must be balanced with a release. Because a single hold is placed
699 on such objects when passed to you in an argument list (and released for you
700 when you return), it is legal to reference and even to invoke such a
701 function without first placing an additional hold on it.
702
703 ### void v8plus_jsfunc_rele(v8plus_jsfunc_t f)
704
705 Releases a hold placed by `v8plus_jsfunc_hold()`.
706
707 ### void v8plus_defer(void *op, void *ctx, worker, completion)
708
709 Enqueues work to be performed in the Node.js shared thread pool. The object
710 `op` and context `ctx` are passed as arguments to `worker` executing in a
711 thread from that pool. The same two arguments, along with the worker's
712 return value, are passed to `completion` executing in the main event loop
713 thread. See example above.
714
715 ### nvlist_t *v8plus_call(v8plus_jsfunc_t f, const nvlist_t *ap)
716
717 Calls the JavaScript function referred to by `f` with encoded arguments
718 `ap`. The return value is the encoded return value of the function. The
719 argument and return value encoding match the encodings that are used by C
720 functions that provide methods.
721
722 ### nvlist_t *v8plus_method_call(void *op, const char *name, const nvlist_t *ap)
723
724 Calls the method named by `name` in the native object `op` with encoded
725 argument list `ap`. The method must exist and must be a JavaScript
726 function. Such functions may be attached by JavaScript code as in the event
727 emitter example above. The effects of using this function to call a native
728 method are undefined.
729
730 As JavaScript functions must be called from the event loop thread,
731 `v8plus_method_call()` contains logic to determine whether we are in the
732 correct context or not. If we are running on some other thread we will
733 queue the request and sleep, waiting for the event loop thread to make the
734 call. In the simple case, where we are already in the correct thread, we
735 make the call directly.
736
737 ## FAQ
738
739 - Why?
740
741 Because C++ is garbage. Writing good software is challenging enough without
742 trying to understand a bunch of implicit side effects or typing templated
743 identifiers that can't fit in 80 columns without falling afoul of the
744 language's ambiguous grammar. Don't get me started.
745
746 - Why not use [FFI](https://github.com/rbranson/node-ffi)?
747
748 FFI is really cool; it offers us the ability to use C libraries without
749 writing bindings at all. However, it also exposes a lot of C nastiness to
750 JavaScript code, essentially placing the interface boundary in consuming
751 code itself. This pretty much breaks the JavaScript interface model --
752 for example, you can't really have a function that inspects the types of its
753 arguments -- and requires you to write an additional C library anyway if you
754 want or need to do something natively that's not quite what the C library
755 already does. Of course, one could use it to write "bindings" in JavaScript
|
542 various practitioners around the world. In this model, your method or
543 function takes a callback argument and returns immediately after enqueuing a
544 task to run on one of the threads in the Node.js worker thread pool. That
545 task consists of a C function to be run on the worker thread, which may not
546 use any V8 (or v8+) state, and a function to be run in the main event loop
547 thread when that task has completed. The latter function is normally
548 expected to invoke the caller's original callback. In v8+, this takes the
549 following form:
550
551 void *
552 async_worker(void *cop, void *ctxp)
553 {
554 my_object_t *op = cop;
555 my_context_t *cp = ctxp;
556 my_result_t *rp = ...;
557
558 /*
559 * In thread pool context -- do not call any of the
560 * following functions:
561 * v8plus_obj_hold()
562 * v8plus_obj_rele_direct()
563 * v8plus_jsfunc_hold()
564 * v8plus_jsfunc_rele_direct()
565 * v8plus_call_direct()
566 * v8plus_method_call_direct()
567 * v8plus_defer()
568 *
569 * If you touch anything inside op, you may need locking to
570 * protect against functions called in the main thread.
571 */
572 ...
573
574 return (rp);
575 }
576
577 void
578 async_completion(void *cop, void *ctxp, void *resp)
579 {
580 my_object_t *op = cop;
581 my_context_t *cp = ctxp;
582 my_result_t *rp = resp;
583 nvlist_t *cbap;
584 nvlist_t *cbrp;
585
671 nvlist_free(eap);
672 nvlist_free(erp);
673 }
674
675 This example will generate an event named "my_event" and propagate it to
676 listeners registered with the `MyObjectWrapper` instance. If additional
677 arguments are associated with the event, they may be added to `eap` and will
678 also be passed along to listeners as arguments to their callbacks.
679
680 ### void v8plus_obj_hold(const void *op)
681
682 Places a hold on the V8 representation of the specified C object. This is
683 rarely necessary; `v8plus_defer()` performs this action for you, but other
684 asynchronous mechanisms may require it. If you are returning from a method
685 call but have stashed a reference to the object somewhere and are not
686 calling `v8plus_defer()`, you must call this first. Holds and releases must
687 be balanced. Use of the object within a thread after releasing is a bug.
688
689 ### void v8plus_obj_rele(const void *op)
690
691 Releases a hold placed by `v8plus_obj_hold()`. This function may be called
692 safely from any thread; releases from threads other than the main event loop
693 are non-blocking and will occur some time in the future.
694
695 ### void v8plus_jsfunc_hold(v8plus_jsfunc_t f)
696
697 Places a hold on the V8 representation of the specified JavaScript function.
698 This is required when returning from a C function that has stashed a
699 reference to the function, typically to use it asynchronously as a callback.
700 All holds must be balanced with a release. Because a single hold is placed
701 on such objects when passed to you in an argument list (and released for you
702 when you return), it is legal to reference and even to invoke such a
703 function without first placing an additional hold on it.
704
705 ### void v8plus_jsfunc_rele(v8plus_jsfunc_t f)
706
707 Releases a hold placed by `v8plus_jsfunc_hold()`. This function may be called
708 safely from any thread; releases from threads other than the main event loop
709 thread are non-blocking and will occur some time in the future.
710
711 ### void v8plus_defer(void *op, void *ctx, worker, completion)
712
713 Enqueues work to be performed in the Node.js shared thread pool. The object
714 `op` and context `ctx` are passed as arguments to `worker` executing in a
715 thread from that pool. The same two arguments, along with the worker's
716 return value, are passed to `completion` executing in the main event loop
717 thread. See example above.
718
719 ### nvlist_t *v8plus_call(v8plus_jsfunc_t f, const nvlist_t *ap)
720
721 Calls the JavaScript function referred to by `f` with encoded arguments
722 `ap`. The return value is the encoded return value of the function. The
723 argument and return value encoding match the encodings that are used by C
724 functions that provide methods.
725
726 As JavaScript functions must be called from the event loop thread,
727 `v8plus_call()` contains logic to determine whether we are in the
728 correct context or not. If we are running on some other thread we will
729 queue the request and sleep, waiting for the event loop thread to make the
730 call. In the simple case, where we are already in the correct thread, we
731 make the call directly.
732
733 Note that when passing JavaScript functions around as callbacks, you must use
734 first use `v8plus_jsfunc_hold()` from within the main event loop thread. Once
735 finished with the function, you may pass it to `v8plus_jsfunc_rele()` from any
736 thread to clean up.
737
738 ### nvlist_t *v8plus_method_call(void *op, const char *name, const nvlist_t *ap)
739
740 Calls the method named by `name` in the native object `op` with encoded
741 argument list `ap`. The method must exist and must be a JavaScript
742 function. Such functions may be attached by JavaScript code as in the event
743 emitter example above. The effects of using this function to call a native
744 method are undefined.
745
746 When called from threads other than the main event loop thread,
747 `v8plus_method_call()` uses the same queue-and-block logic as described above
748 in `v8plus_call()`.
749
750 ## FAQ
751
752 - Why?
753
754 Because C++ is garbage. Writing good software is challenging enough without
755 trying to understand a bunch of implicit side effects or typing templated
756 identifiers that can't fit in 80 columns without falling afoul of the
757 language's ambiguous grammar. Don't get me started.
758
759 - Why not use [FFI](https://github.com/rbranson/node-ffi)?
760
761 FFI is really cool; it offers us the ability to use C libraries without
762 writing bindings at all. However, it also exposes a lot of C nastiness to
763 JavaScript code, essentially placing the interface boundary in consuming
764 code itself. This pretty much breaks the JavaScript interface model --
765 for example, you can't really have a function that inspects the types of its
766 arguments -- and requires you to write an additional C library anyway if you
767 want or need to do something natively that's not quite what the C library
768 already does. Of course, one could use it to write "bindings" in JavaScript
|