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

@@ -27,10 +27,11 @@
 
 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,19 +452,22 @@
 
         return (rp);
 }
 
 extern "C" nvlist_t *
-v8plus_method_call(void *cop, const char *name, const nvlist_t *lp)
+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,10 +487,81 @@
         }
 
         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;