Print this page
XXX error handling cleanup
XXX rework to avoid changing api
XXX well, it works now...
XXX first cut of crosscall


  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