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()
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
586 ...
634 var util = require('util');
635 var binding = require('./native_binding');
636 var events = require('events');
637
638 function
639 MyObjectWrapper()
640 {
641 var self = this;
642
643 events.EventEmitter.call(this);
644 this._native = binding._create.apply(this,
645 Array.prototype.slice.call(arguments));
646 this._native._emit = function () {
647 var args = Array.prototype.slice.call(arguments);
648 self.emit.apply(self, args);
649 };
650 }
651 util.inherits(MyObjectWrapper, events.EventEmitter);
652
653 Then, in C code, you must arrange for libuv to call a C function in the
654 context of the main event loop. How to do this depends on what type of
655 asynchronous event you are waiting for; for example, the `uv_poll` mechanism
656 will call you back in the appropriate context when a file descriptor becomes
657 readable or writable. Because libuv is a C library, you can easily use
658 these interfaces directly in your v8+ addon. Your libuv callback might then
659 contain code looking something like this:
660
661 nvlist_t *eap;
662 nvlist_t *erp;
663 my_object_t *op = ...;
664 ...
665 eap = v8plus_obj(
666 V8PLUS_TYPE_STRING, "0", "my_event",
667 ...,
668 V8PLUS_TYPE_NONE);
669
670 if (eap != NULL) {
671 erp = v8plus_method_call(op, "_emit", eap);
672 nvlist_free(eap);
673 nvlist_free(erp);
674 }
675
676 This example will generate an event named "my_event" and propagate it to
677 listeners registered with the `MyObjectWrapper` instance. If additional
678 arguments are associated with the event, they may be added to `eap` and will
679 also be passed along to listeners as arguments to their callbacks.
711 `op` and context `ctx` are passed as arguments to `worker` executing in a
712 thread from that pool. The same two arguments, along with the worker's
713 return value, are passed to `completion` executing in the main event loop
714 thread. See example above.
715
716 ### nvlist_t *v8plus_call(v8plus_jsfunc_t f, const nvlist_t *ap)
717
718 Calls the JavaScript function referred to by `f` with encoded arguments
719 `ap`. The return value is the encoded return value of the function. The
720 argument and return value encoding match the encodings that are used by C
721 functions that provide methods.
722
723 ### nvlist_t *v8plus_method_call(void *op, const char *name, const nvlist_t *ap)
724
725 Calls the method named by `name` in the native object `op` with encoded
726 argument list `ap`. The method must exist and must be a JavaScript
727 function. Such functions may be attached by JavaScript code as in the event
728 emitter example above. The effects of using this function to call a native
729 method are undefined.
730
731 ## FAQ
732
733 - Why?
734
735 Because C++ is garbage. Writing good software is challenging enough without
736 trying to understand a bunch of implicit side effects or typing templated
737 identifiers that can't fit in 80 columns without falling afoul of the
738 language's ambiguous grammar. Don't get me started.
739
740 - Why not use [FFI](https://github.com/rbranson/node-ffi)?
741
742 FFI is really cool; it offers us the ability to use C libraries without
743 writing bindings at all. However, it also exposes a lot of C nastiness to
744 JavaScript code, essentially placing the interface boundary in consuming
745 code itself. This pretty much breaks the JavaScript interface model --
746 for example, you can't really have a function that inspects the types of its
747 arguments -- and requires you to write an additional C library anyway if you
748 want or need to do something natively that's not quite what the C library
749 already does. Of course, one could use it to write "bindings" in JavaScript
750 that actually look like a JavaScript interface, which may end up being the
|
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
586 ...
634 var util = require('util');
635 var binding = require('./native_binding');
636 var events = require('events');
637
638 function
639 MyObjectWrapper()
640 {
641 var self = this;
642
643 events.EventEmitter.call(this);
644 this._native = binding._create.apply(this,
645 Array.prototype.slice.call(arguments));
646 this._native._emit = function () {
647 var args = Array.prototype.slice.call(arguments);
648 self.emit.apply(self, args);
649 };
650 }
651 util.inherits(MyObjectWrapper, events.EventEmitter);
652
653 Then, in C code, you must arrange for libuv to call a C function in the
654 context of the main event loop. The function `v8plus_method_call()` is safe
655 to call from any thread: depending on the context in which it is invoked, it
656 will either make the call directly or queue the call in the main event loop
657 and block on a reply. Simply arrange to call back into your JavaScript
658 object when you wish to post an event:
659
660 nvlist_t *eap;
661 nvlist_t *erp;
662 my_object_t *op = ...;
663 ...
664 eap = v8plus_obj(
665 V8PLUS_TYPE_STRING, "0", "my_event",
666 ...,
667 V8PLUS_TYPE_NONE);
668
669 if (eap != NULL) {
670 erp = v8plus_method_call(op, "_emit", eap);
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.
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
756 that actually look like a JavaScript interface, which may end up being the
|