12 #include <node.h>
13 #include <v8.h>
14 #include <unordered_map>
15 #include <string>
16 #include "v8plus_impl.h"
17
18 #define V8PLUS_OBJ_TYPE_MEMBER ".__v8plus_type"
19 #define V8_EXCEPTION_CTOR_FMT \
20 "_ZN2v89Exception%u%sENS_6HandleINS_6StringEEE"
21
22 typedef struct cb_hdl {
23 v8::Handle<v8::Function> ch_hdl;
24 uint_t ch_refs;
25 boolean_t ch_persist;
26 } cb_hdl_t;
27
28 static std::unordered_map<uint64_t, cb_hdl_t> cbhash;
29 static uint64_t cbnext;
30 static void (*__real_nvlist_free)(nvlist_t *);
31
32 static const char *
33 cstr(const v8::String::Utf8Value &v)
34 {
35 return (*v);
36 }
37
38 /*
39 * Convenience macros for adding stuff to an nvlist and returning on failure.
40 */
41 #define LA_U(_l, _n, _e) \
42 if (((_e) = nvlist_add_boolean((_l), (_n))) != 0) \
43 return (_e)
44
45 #define LA_N(_l, _n, _e) \
46 if (((_e) = nvlist_add_byte((_l), (_n), 0)) != 0) \
47 return (_e)
48
49 #define LA_V(_l, _t, _n, _v, _e) \
50 if (((_e) = nvlist_add_##_t((_l), (_n), (_v))) != 0) \
51 return (_e)
436
437 v8::TryCatch tc;
438 res = it->second.ch_hdl->Call(v8::Context::GetCurrent()->Global(),
439 argc, argv);
440 if (tc.HasCaught()) {
441 err = nvlist_add_v8_Value(rp, "err", tc.Exception());
442 tc.Reset();
443 if (err != 0) {
444 nvlist_free(rp);
445 return (v8plus_nverr(err, "err"));
446 }
447 } else if ((err = nvlist_add_v8_Value(rp, "res", res)) != 0) {
448 nvlist_free(rp);
449 return (v8plus_nverr(err, "res"));
450 }
451
452 return (rp);
453 }
454
455 extern "C" nvlist_t *
456 v8plus_method_call(void *cop, const char *name, const nvlist_t *lp)
457 {
458 v8plus::ObjectWrap *op = v8plus::ObjectWrap::objlookup(cop);
459 const int max_argc = nvlist_length(lp);
460 int argc, err;
461 v8::Handle<v8::Value> argv[max_argc];
462 v8::Handle<v8::Value> res;
463 nvlist_t *rp;
464
465 argc = max_argc;
466 nvlist_to_v8_argv(lp, &argc, argv);
467
468 if ((err = nvlist_alloc(&rp, NV_UNIQUE_NAME, 0)) != 0)
469 return (v8plus_nverr(err, NULL));
470
471 v8::TryCatch tc;
472 res = op->call(name, argc, argv);
473 if (tc.HasCaught()) {
474 err = nvlist_add_v8_Value(rp, "err", tc.Exception());
475 tc.Reset();
476 if (err != 0) {
477 nvlist_free(rp);
478 return (v8plus_nverr(err, "err"));
479 }
480 } else if ((err = nvlist_add_v8_Value(rp, "res", res)) != 0) {
481 nvlist_free(rp);
482 return (v8plus_nverr(err, "res"));
483 }
484
485 return (rp);
486 }
487
488 extern "C" int
489 nvlist_lookup_v8plus_jsfunc(const nvlist_t *lp, const char *name,
490 v8plus_jsfunc_t *vp)
491 {
492 uint64_t *lvp;
493 uint_t nv;
494 int err;
495
496 err = nvlist_lookup_uint64_array(const_cast<nvlist_t *>(lp),
497 name, &lvp, &nv);
498 if (err != 0)
499 return (err);
500
501 if (nv != 1)
502 v8plus_panic("bad array size %u for callback hash tag", nv);
503
504 *vp = *lvp;
505 return (0);
506 }
507
|
12 #include <node.h>
13 #include <v8.h>
14 #include <unordered_map>
15 #include <string>
16 #include "v8plus_impl.h"
17
18 #define V8PLUS_OBJ_TYPE_MEMBER ".__v8plus_type"
19 #define V8_EXCEPTION_CTOR_FMT \
20 "_ZN2v89Exception%u%sENS_6HandleINS_6StringEEE"
21
22 typedef struct cb_hdl {
23 v8::Handle<v8::Function> ch_hdl;
24 uint_t ch_refs;
25 boolean_t ch_persist;
26 } cb_hdl_t;
27
28 static std::unordered_map<uint64_t, cb_hdl_t> cbhash;
29 static uint64_t cbnext;
30 static void (*__real_nvlist_free)(nvlist_t *);
31
32
33 static const char *
34 cstr(const v8::String::Utf8Value &v)
35 {
36 return (*v);
37 }
38
39 /*
40 * Convenience macros for adding stuff to an nvlist and returning on failure.
41 */
42 #define LA_U(_l, _n, _e) \
43 if (((_e) = nvlist_add_boolean((_l), (_n))) != 0) \
44 return (_e)
45
46 #define LA_N(_l, _n, _e) \
47 if (((_e) = nvlist_add_byte((_l), (_n), 0)) != 0) \
48 return (_e)
49
50 #define LA_V(_l, _t, _n, _v, _e) \
51 if (((_e) = nvlist_add_##_t((_l), (_n), (_v))) != 0) \
52 return (_e)
437
438 v8::TryCatch tc;
439 res = it->second.ch_hdl->Call(v8::Context::GetCurrent()->Global(),
440 argc, argv);
441 if (tc.HasCaught()) {
442 err = nvlist_add_v8_Value(rp, "err", tc.Exception());
443 tc.Reset();
444 if (err != 0) {
445 nvlist_free(rp);
446 return (v8plus_nverr(err, "err"));
447 }
448 } else if ((err = nvlist_add_v8_Value(rp, "res", res)) != 0) {
449 nvlist_free(rp);
450 return (v8plus_nverr(err, "res"));
451 }
452
453 return (rp);
454 }
455
456 extern "C" nvlist_t *
457 v8plus_method_call_direct(void *cop, const char *name, const nvlist_t *lp)
458 {
459 v8plus::ObjectWrap *op = v8plus::ObjectWrap::objlookup(cop);
460 const int max_argc = nvlist_length(lp);
461 int argc, err;
462 v8::Handle<v8::Value> argv[max_argc];
463 v8::Handle<v8::Value> res;
464 nvlist_t *rp;
465
466 if (v8plus::ObjectWrap::in_event_thread() != _B_TRUE)
467 v8plus_panic("direct method call outside of event loop");
468
469 argc = max_argc;
470 nvlist_to_v8_argv(lp, &argc, argv);
471
472 if ((err = nvlist_alloc(&rp, NV_UNIQUE_NAME, 0)) != 0)
473 return (v8plus_nverr(err, NULL));
474
475 v8::TryCatch tc;
476 res = op->call(name, argc, argv);
477 if (tc.HasCaught()) {
478 err = nvlist_add_v8_Value(rp, "err", tc.Exception());
479 tc.Reset();
480 if (err != 0) {
481 nvlist_free(rp);
482 return (v8plus_nverr(err, "err"));
483 }
484 } else if ((err = nvlist_add_v8_Value(rp, "res", res)) != 0) {
485 nvlist_free(rp);
486 return (v8plus_nverr(err, "res"));
487 }
488
489 return (rp);
490 }
491
492 extern "C" void
493 v8plus_async_callback(uv_async_t *async, __attribute__((unused)) int status)
494 {
495 if (v8plus::ObjectWrap::in_event_thread() != _B_TRUE)
496 v8plus_panic("async callback called outside of event loop");
497
498 for (;;) {
499 v8plus_async_call_t *ac;
500
501 if ((ac = v8plus::ObjectWrap::next_async_call()) == NULL)
502 break;
503
504 if (pthread_mutex_lock(&ac->ac_mtx) != 0)
505 v8plus_panic("could not lock async call mutex");
506
507 if (ac->ac_run == _B_TRUE)
508 v8plus_panic("async call already run");
509
510 ac->ac_return = v8plus_method_call_direct(ac->ac_cop,
511 ac->ac_name, ac->ac_lp);
512 ac->ac_run = _B_TRUE;
513
514 if (pthread_cond_broadcast(&ac->ac_cv) != 0)
515 v8plus_panic("could not signal async call condvar");
516 if (pthread_mutex_unlock(&ac->ac_mtx) != 0)
517 v8plus_panic("could not unlock async call mutex");
518 }
519 }
520
521 extern "C" nvlist_t *
522 v8plus_method_call(void *cop, const char *name, const nvlist_t *lp)
523 {
524 v8plus_async_call_t ac;
525
526 if (v8plus::ObjectWrap::in_event_thread() == _B_TRUE) {
527 /*
528 * We're running in the event loop thread, so we can make the
529 * call directly.
530 */
531 return (v8plus_method_call_direct(cop, name, lp));
532 }
533
534 /*
535 * As we cannot manipulate v8plus/V8/Node structures directly from
536 * outside the event loop thread, we push the call arguments onto a
537 * queue and post to the event loop thread. We then sleep on our
538 * condition variable until the event loop thread makes the call
539 * for us and wakes us up.
540 */
541 ac.ac_cop = cop;
542 ac.ac_name = name;
543 ac.ac_lp = lp;
544 if (pthread_mutex_init(&ac.ac_mtx, NULL) != 0)
545 v8plus_panic("could not init async call mutex");
546 if (pthread_cond_init(&ac.ac_cv, NULL) != 0)
547 v8plus_panic("could not init async call condvar");
548 ac.ac_run = _B_FALSE;
549 ac.ac_return = NULL;
550
551 v8plus::ObjectWrap::post_async_call(&ac);
552
553 if (pthread_mutex_lock(&ac.ac_mtx) != 0)
554 v8plus_panic("could not lock async call mutex");
555 while (ac.ac_run == _B_FALSE) {
556 if (pthread_cond_wait(&ac.ac_cv, &ac.ac_mtx) != 0)
557 v8plus_panic("could not wait on async call condvar");
558 }
559
560 return (ac.ac_return);
561 }
562
563 extern "C" int
564 nvlist_lookup_v8plus_jsfunc(const nvlist_t *lp, const char *name,
565 v8plus_jsfunc_t *vp)
566 {
567 uint64_t *lvp;
568 uint_t nv;
569 int err;
570
571 err = nvlist_lookup_uint64_array(const_cast<nvlist_t *>(lp),
572 name, &lvp, &nv);
573 if (err != 0)
574 return (err);
575
576 if (nv != 1)
577 v8plus_panic("bad array size %u for callback hash tag", nv);
578
579 *vp = *lvp;
580 return (0);
581 }
582
|