Print this page
XXX rework to avoid changing api
XXX well, it works now...

@@ -16,10 +16,16 @@
 v8::Persistent<v8::Function> v8plus::ObjectWrap::_constructor;
 v8plus_method_descr_t *v8plus::ObjectWrap::_mtbl;
 v8plus_static_descr_t *v8plus::ObjectWrap::_stbl;
 std::unordered_map<void *, v8plus::ObjectWrap *> v8plus::ObjectWrap::_objhash;
 
+uv_async_t v8plus::ObjectWrap::_uv_async;
+pthread_mutex_t v8plus::ObjectWrap::_callq_mutex;
+std::queue<v8plus_async_call_t *> v8plus::ObjectWrap::_callq;
+boolean_t v8plus::ObjectWrap::_crossthread_init_done = _B_FALSE;
+unsigned long v8plus::ObjectWrap::_uv_event_thread;
+
 static char *
 function_name(const char *lambda)
 {
         char *fn;
         size_t len;

@@ -111,10 +117,28 @@
         nvlist_t *c_args;
 
         if ((c_args = v8plus::v8_Arguments_to_nvlist(args)) == NULL)
                 return (V8PLUS_THROW_DEFAULT());
 
+        if (_crossthread_init_done == _B_FALSE) {
+                /*
+                 * Initialise structures for off-event-loop method calls.
+                 *
+                 * Note that uv_async_init() must be called inside the libuv
+                 * Event Loop, so we do it here.  We also want to record the
+                 * thread ID of the Event Loop thread so as to determine what
+                 * kind of method calls to make later.
+                 */
+                _uv_event_thread = pthread_self();
+                if (uv_async_init(uv_default_loop(), &_uv_async,
+                    v8plus_async_callback) != 0)
+                        v8plus_panic("unable to initialise uv_async_t");
+                if (pthread_mutex_init(&_callq_mutex, NULL) != 0)
+                        v8plus_panic("unable to initialise mutex");
+                _crossthread_init_done = _B_TRUE;
+        }
+
         c_excp = v8plus_ctor(c_args, &op->_c_impl);
         nvlist_free(c_args);
         if (op->_c_impl == NULL) {
                 if (c_excp == NULL) {
                         return (V8PLUS_THROW_DEFAULT());

@@ -310,10 +334,52 @@
 v8plus::ObjectWrap::public_Unref(void)
 {
         this->Unref();
 }
 
+boolean_t
+v8plus::ObjectWrap::in_event_thread(void)
+{
+        if (_crossthread_init_done != _B_TRUE)
+                v8plus_panic("cross thread call init not done!");
+
+        return (_uv_event_thread == pthread_self() ? _B_TRUE : _B_FALSE);
+}
+
+v8plus_async_call_t *
+v8plus::ObjectWrap::next_async_call(void)
+{
+        v8plus_async_call_t *ret = NULL;
+
+        if (pthread_mutex_lock(&_callq_mutex) != 0)
+                v8plus_panic("could not lock callq mutex");
+
+        if (!_callq.empty()) {
+                ret = _callq.front();
+                _callq.pop();
+        }
+
+        if (pthread_mutex_unlock(&_callq_mutex) != 0)
+                v8plus_panic("could not release callq mutex");
+
+        return (ret);
+}
+
+void
+v8plus::ObjectWrap::post_async_call(v8plus_async_call_t *ac)
+{
+        if (pthread_mutex_lock(&_callq_mutex) != 0)
+                v8plus_panic("could not lock callq mutex");
+
+        _callq.push(ac);
+
+        if (pthread_mutex_unlock(&_callq_mutex) != 0)
+                v8plus_panic("could not release callq mutex");
+
+        uv_async_send(&_uv_async);
+}
+
 extern "C" void
 init(v8::Handle<v8::Object> target)
 {
         v8plus::ObjectWrap::init(target);
 }