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)
{