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

*** 27,36 **** --- 27,37 ---- static std::unordered_map<uint64_t, cb_hdl_t> cbhash; static uint64_t cbnext; static void (*__real_nvlist_free)(nvlist_t *); + static const char * cstr(const v8::String::Utf8Value &v) { return (*v); }
*** 451,469 **** return (rp); } extern "C" nvlist_t * ! v8plus_method_call(void *cop, const char *name, const nvlist_t *lp) { v8plus::ObjectWrap *op = v8plus::ObjectWrap::objlookup(cop); const int max_argc = nvlist_length(lp); int argc, err; v8::Handle<v8::Value> argv[max_argc]; v8::Handle<v8::Value> res; nvlist_t *rp; argc = max_argc; nvlist_to_v8_argv(lp, &argc, argv); if ((err = nvlist_alloc(&rp, NV_UNIQUE_NAME, 0)) != 0) return (v8plus_nverr(err, NULL)); --- 452,473 ---- return (rp); } extern "C" nvlist_t * ! v8plus_method_call_direct(void *cop, const char *name, const nvlist_t *lp) { v8plus::ObjectWrap *op = v8plus::ObjectWrap::objlookup(cop); const int max_argc = nvlist_length(lp); int argc, err; v8::Handle<v8::Value> argv[max_argc]; v8::Handle<v8::Value> res; nvlist_t *rp; + if (v8plus::ObjectWrap::in_event_thread() != _B_TRUE) + v8plus_panic("direct method call outside of event loop"); + argc = max_argc; nvlist_to_v8_argv(lp, &argc, argv); if ((err = nvlist_alloc(&rp, NV_UNIQUE_NAME, 0)) != 0) return (v8plus_nverr(err, NULL));
*** 483,492 **** --- 487,567 ---- } return (rp); } + extern "C" void + v8plus_async_callback(uv_async_t *async, __attribute__((unused)) int status) + { + if (v8plus::ObjectWrap::in_event_thread() != _B_TRUE) + v8plus_panic("async callback called outside of event loop"); + + for (;;) { + v8plus_async_call_t *ac; + + if ((ac = v8plus::ObjectWrap::next_async_call()) == NULL) + break; + + if (pthread_mutex_lock(&ac->ac_mtx) != 0) + v8plus_panic("could not lock async call mutex"); + + if (ac->ac_run == _B_TRUE) + v8plus_panic("async call already run"); + + ac->ac_return = v8plus_method_call_direct(ac->ac_cop, + ac->ac_name, ac->ac_lp); + ac->ac_run = _B_TRUE; + + if (pthread_cond_broadcast(&ac->ac_cv) != 0) + v8plus_panic("could not signal async call condvar"); + if (pthread_mutex_unlock(&ac->ac_mtx) != 0) + v8plus_panic("could not unlock async call mutex"); + } + } + + extern "C" nvlist_t * + v8plus_method_call(void *cop, const char *name, const nvlist_t *lp) + { + v8plus_async_call_t ac; + + if (v8plus::ObjectWrap::in_event_thread() == _B_TRUE) { + /* + * We're running in the event loop thread, so we can make the + * call directly. + */ + return (v8plus_method_call_direct(cop, name, lp)); + } + + /* + * As we cannot manipulate v8plus/V8/Node structures directly from + * outside the event loop thread, we push the call arguments onto a + * queue and post to the event loop thread. We then sleep on our + * condition variable until the event loop thread makes the call + * for us and wakes us up. + */ + ac.ac_cop = cop; + ac.ac_name = name; + ac.ac_lp = lp; + if (pthread_mutex_init(&ac.ac_mtx, NULL) != 0) + v8plus_panic("could not init async call mutex"); + if (pthread_cond_init(&ac.ac_cv, NULL) != 0) + v8plus_panic("could not init async call condvar"); + ac.ac_run = _B_FALSE; + ac.ac_return = NULL; + + v8plus::ObjectWrap::post_async_call(&ac); + + if (pthread_mutex_lock(&ac.ac_mtx) != 0) + v8plus_panic("could not lock async call mutex"); + while (ac.ac_run == _B_FALSE) { + if (pthread_cond_wait(&ac.ac_cv, &ac.ac_mtx) != 0) + v8plus_panic("could not wait on async call condvar"); + } + + return (ac.ac_return); + } + extern "C" int nvlist_lookup_v8plus_jsfunc(const nvlist_t *lp, const char *name, v8plus_jsfunc_t *vp) { uint64_t *lvp;