Print this page
joyent/v8plus#7 v8plus should not hold the event loop open forever

@@ -29,15 +29,18 @@
     STAILQ_HEAD_INITIALIZER(_v8plus_callq);
 static pthread_mutex_t _v8plus_callq_mtx;
 static pthread_t _v8plus_uv_event_thread;
 static uv_async_t _v8plus_uv_async;
 
+static int _v8plus_eventloop_refcount;
+
 typedef enum v8plus_async_call_type {
         ACT_OBJECT_CALL = 1,
         ACT_OBJECT_RELEASE,
         ACT_JSFUNC_CALL,
         ACT_JSFUNC_RELEASE,
+        ACT_EVENTLOOP_RELEASE
 } v8plus_async_call_type_t;
 
 typedef enum v8plus_async_call_flags {
         ACF_COMPLETED   = 0x01,
         ACF_NOREPLY     = 0x02

@@ -119,10 +122,13 @@
                             vac->vac_func, vac->vac_lp);
                         break;
                 case ACT_JSFUNC_RELEASE:
                         v8plus_jsfunc_rele_direct(vac->vac_func);
                         break;
+                case ACT_EVENTLOOP_RELEASE:
+                        v8plus_eventloop_rele_direct();
+                        break;
                 }
 
                 if (vac->vac_flags & ACF_NOREPLY) {
                         /*
                          * The caller posted this event and is not sleeping

@@ -302,10 +308,53 @@
         if (uv_async_init(uv_default_loop(), &_v8plus_uv_async,
             v8plus_async_callback) != 0)
                 v8plus_panic("unable to initialise uv_async_t");
         if (pthread_mutex_init(&_v8plus_callq_mtx, NULL) != 0)
                 v8plus_panic("unable to initialise mutex");
+
+        /*
+         * If we do not unreference the async handle, then its mere
+         * existence will keep the event loop open forever.  If the consumer
+         * _wants_ this behaviour, they may call v8plus_eventloop_hold()
+         * from the event loop thread.
+         */
+        uv_unref((uv_handle_t *)&_v8plus_uv_async);
+}
+
+void
+v8plus_eventloop_hold(void)
+{
+        ++_v8plus_eventloop_refcount;
+        uv_ref((uv_handle_t *)&_v8plus_uv_async);
+}
+
+void
+v8plus_eventloop_rele_direct(void)
+{
+        if (--_v8plus_eventloop_refcount < 1) {
+                _v8plus_eventloop_refcount = 0;
+                uv_unref((uv_handle_t *)&_v8plus_uv_async);
+        }
+}
+
+void
+v8plus_eventloop_rele(void)
+{
+        v8plus_async_call_t *vac;
+
+        if (v8plus_in_event_thread() == B_TRUE) {
+                return (v8plus_eventloop_rele_direct());
+        }
+
+        vac = calloc(1, sizeof (*vac));
+        if (vac == NULL)
+                v8plus_panic("could not allocate async call structure");
+
+        vac->vac_type = ACT_EVENTLOOP_RELEASE;
+        vac->vac_flags = ACF_NOREPLY;
+
+        (void) v8plus_cross_thread_call(vac);
 }
 
 nvlist_t *
 v8plus_verror(v8plus_errno_t e, const char *fmt, va_list ap)
 {