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


  14 #include <pthread.h>
  15 #include "v8plus_glue.h"
  16 
  17 __thread v8plus_errno_t _v8plus_errno;
  18 __thread char _v8plus_errmsg[V8PLUS_ERRMSG_LEN];
  19 
  20 typedef struct v8plus_uv_ctx {
  21         void *vuc_obj;
  22         void *vuc_ctx;
  23         void *vuc_result;
  24         v8plus_worker_f vuc_worker;
  25         v8plus_completion_f vuc_completion;
  26 } v8plus_uv_ctx_t;
  27 
  28 static STAILQ_HEAD(v8plus_callq_head, v8plus_async_call) _v8plus_callq =
  29     STAILQ_HEAD_INITIALIZER(_v8plus_callq);
  30 static pthread_mutex_t _v8plus_callq_mtx;
  31 static pthread_t _v8plus_uv_event_thread;
  32 static uv_async_t _v8plus_uv_async;
  33 


  34 typedef enum v8plus_async_call_type {
  35         ACT_OBJECT_CALL = 1,
  36         ACT_OBJECT_RELEASE,
  37         ACT_JSFUNC_CALL,
  38         ACT_JSFUNC_RELEASE,

  39 } v8plus_async_call_type_t;
  40 
  41 typedef enum v8plus_async_call_flags {
  42         ACF_COMPLETED   = 0x01,
  43         ACF_NOREPLY     = 0x02
  44 } v8plus_async_call_flags_t;
  45 
  46 
  47 typedef struct v8plus_async_call {
  48         v8plus_async_call_type_t vac_type;
  49         v8plus_async_call_flags_t vac_flags;
  50 
  51         /*
  52          * For ACT_OBJECT_{CALL,RELEASE}:
  53          */
  54         void *vac_cop;
  55         const char *vac_name;
  56         /*
  57          * For ACT_JSFUNC_{CALL,RELEASE}:
  58          */


 104                  * Run the queued method:
 105                  */
 106                 if (vac->vac_flags & ACF_COMPLETED)
 107                         v8plus_panic("async call already run");
 108 
 109                 switch (vac->vac_type) {
 110                 case ACT_OBJECT_CALL:
 111                         vac->vac_return = v8plus_method_call_direct(
 112                             vac->vac_cop, vac->vac_name, vac->vac_lp);
 113                         break;
 114                 case ACT_OBJECT_RELEASE:
 115                         v8plus_obj_rele_direct(vac->vac_cop);
 116                         break;
 117                 case ACT_JSFUNC_CALL:
 118                         vac->vac_return = v8plus_call_direct(
 119                             vac->vac_func, vac->vac_lp);
 120                         break;
 121                 case ACT_JSFUNC_RELEASE:
 122                         v8plus_jsfunc_rele_direct(vac->vac_func);
 123                         break;



 124                 }
 125 
 126                 if (vac->vac_flags & ACF_NOREPLY) {
 127                         /*
 128                          * The caller posted this event and is not sleeping
 129                          * on a reply.  Just free the call structure and move
 130                          * on.
 131                          */
 132                         free(vac);
 133                         if (vac->vac_lp != NULL)
 134                                 nvlist_free((nvlist_t *)vac->vac_lp);
 135                         continue;
 136                 }
 137 
 138                 if (pthread_mutex_lock(&vac->vac_mtx) != 0)
 139                         v8plus_panic("could not lock async call mutex");
 140                 vac->vac_flags |= ACF_COMPLETED;
 141                 if (pthread_cond_broadcast(&vac->vac_cv) != 0)
 142                         v8plus_panic("could not signal async call condvar");
 143                 if (pthread_mutex_unlock(&vac->vac_mtx) != 0)


 287 
 288         (void) v8plus_cross_thread_call(vac);
 289 }
 290 
 291 /*
 292  * Initialise structures for off-event-loop method calls.
 293  *
 294  * Note that uv_async_init() must be called inside the libuv event loop, so we
 295  * do it here.  We also want to record the thread ID of the Event Loop thread
 296  * so as to determine what kind of method calls to make later.
 297  */
 298 void
 299 v8plus_crossthread_init(void)
 300 {
 301         _v8plus_uv_event_thread = pthread_self();
 302         if (uv_async_init(uv_default_loop(), &_v8plus_uv_async,
 303             v8plus_async_callback) != 0)
 304                 v8plus_panic("unable to initialise uv_async_t");
 305         if (pthread_mutex_init(&_v8plus_callq_mtx, NULL) != 0)
 306                 v8plus_panic("unable to initialise mutex");











































 307 }
 308 
 309 nvlist_t *
 310 v8plus_verror(v8plus_errno_t e, const char *fmt, va_list ap)
 311 {
 312         if (fmt == NULL) {
 313                 if (e == V8PLUSERR_NOERROR) {
 314                         *_v8plus_errmsg = '\0';
 315                 } else {
 316                         (void) snprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN,
 317                             "%s", v8plus_strerror(e));
 318                 }
 319         } else {
 320                 (void) vsnprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN, fmt, ap);
 321         }
 322         _v8plus_errno = e;
 323 
 324         return (NULL);
 325 }
 326 




  14 #include <pthread.h>
  15 #include "v8plus_glue.h"
  16 
  17 __thread v8plus_errno_t _v8plus_errno;
  18 __thread char _v8plus_errmsg[V8PLUS_ERRMSG_LEN];
  19 
  20 typedef struct v8plus_uv_ctx {
  21         void *vuc_obj;
  22         void *vuc_ctx;
  23         void *vuc_result;
  24         v8plus_worker_f vuc_worker;
  25         v8plus_completion_f vuc_completion;
  26 } v8plus_uv_ctx_t;
  27 
  28 static STAILQ_HEAD(v8plus_callq_head, v8plus_async_call) _v8plus_callq =
  29     STAILQ_HEAD_INITIALIZER(_v8plus_callq);
  30 static pthread_mutex_t _v8plus_callq_mtx;
  31 static pthread_t _v8plus_uv_event_thread;
  32 static uv_async_t _v8plus_uv_async;
  33 
  34 static int _v8plus_eventloop_refcount;
  35 
  36 typedef enum v8plus_async_call_type {
  37         ACT_OBJECT_CALL = 1,
  38         ACT_OBJECT_RELEASE,
  39         ACT_JSFUNC_CALL,
  40         ACT_JSFUNC_RELEASE,
  41         ACT_EVENTLOOP_RELEASE
  42 } v8plus_async_call_type_t;
  43 
  44 typedef enum v8plus_async_call_flags {
  45         ACF_COMPLETED   = 0x01,
  46         ACF_NOREPLY     = 0x02
  47 } v8plus_async_call_flags_t;
  48 
  49 
  50 typedef struct v8plus_async_call {
  51         v8plus_async_call_type_t vac_type;
  52         v8plus_async_call_flags_t vac_flags;
  53 
  54         /*
  55          * For ACT_OBJECT_{CALL,RELEASE}:
  56          */
  57         void *vac_cop;
  58         const char *vac_name;
  59         /*
  60          * For ACT_JSFUNC_{CALL,RELEASE}:
  61          */


 107                  * Run the queued method:
 108                  */
 109                 if (vac->vac_flags & ACF_COMPLETED)
 110                         v8plus_panic("async call already run");
 111 
 112                 switch (vac->vac_type) {
 113                 case ACT_OBJECT_CALL:
 114                         vac->vac_return = v8plus_method_call_direct(
 115                             vac->vac_cop, vac->vac_name, vac->vac_lp);
 116                         break;
 117                 case ACT_OBJECT_RELEASE:
 118                         v8plus_obj_rele_direct(vac->vac_cop);
 119                         break;
 120                 case ACT_JSFUNC_CALL:
 121                         vac->vac_return = v8plus_call_direct(
 122                             vac->vac_func, vac->vac_lp);
 123                         break;
 124                 case ACT_JSFUNC_RELEASE:
 125                         v8plus_jsfunc_rele_direct(vac->vac_func);
 126                         break;
 127                 case ACT_EVENTLOOP_RELEASE:
 128                         v8plus_eventloop_rele_direct();
 129                         break;
 130                 }
 131 
 132                 if (vac->vac_flags & ACF_NOREPLY) {
 133                         /*
 134                          * The caller posted this event and is not sleeping
 135                          * on a reply.  Just free the call structure and move
 136                          * on.
 137                          */
 138                         free(vac);
 139                         if (vac->vac_lp != NULL)
 140                                 nvlist_free((nvlist_t *)vac->vac_lp);
 141                         continue;
 142                 }
 143 
 144                 if (pthread_mutex_lock(&vac->vac_mtx) != 0)
 145                         v8plus_panic("could not lock async call mutex");
 146                 vac->vac_flags |= ACF_COMPLETED;
 147                 if (pthread_cond_broadcast(&vac->vac_cv) != 0)
 148                         v8plus_panic("could not signal async call condvar");
 149                 if (pthread_mutex_unlock(&vac->vac_mtx) != 0)


 293 
 294         (void) v8plus_cross_thread_call(vac);
 295 }
 296 
 297 /*
 298  * Initialise structures for off-event-loop method calls.
 299  *
 300  * Note that uv_async_init() must be called inside the libuv event loop, so we
 301  * do it here.  We also want to record the thread ID of the Event Loop thread
 302  * so as to determine what kind of method calls to make later.
 303  */
 304 void
 305 v8plus_crossthread_init(void)
 306 {
 307         _v8plus_uv_event_thread = pthread_self();
 308         if (uv_async_init(uv_default_loop(), &_v8plus_uv_async,
 309             v8plus_async_callback) != 0)
 310                 v8plus_panic("unable to initialise uv_async_t");
 311         if (pthread_mutex_init(&_v8plus_callq_mtx, NULL) != 0)
 312                 v8plus_panic("unable to initialise mutex");
 313 
 314         /*
 315          * If we do not unreference the async handle, then its mere
 316          * existence will keep the event loop open forever.  If the consumer
 317          * _wants_ this behaviour, they may call v8plus_eventloop_hold()
 318          * from the event loop thread.
 319          */
 320         uv_unref((uv_handle_t *)&_v8plus_uv_async);
 321 }
 322 
 323 void
 324 v8plus_eventloop_hold(void)
 325 {
 326         ++_v8plus_eventloop_refcount;
 327         uv_ref((uv_handle_t *)&_v8plus_uv_async);
 328 }
 329 
 330 void
 331 v8plus_eventloop_rele_direct(void)
 332 {
 333         if (--_v8plus_eventloop_refcount < 1) {
 334                 _v8plus_eventloop_refcount = 0;
 335                 uv_unref((uv_handle_t *)&_v8plus_uv_async);
 336         }
 337 }
 338 
 339 void
 340 v8plus_eventloop_rele(void)
 341 {
 342         v8plus_async_call_t *vac;
 343 
 344         if (v8plus_in_event_thread() == B_TRUE) {
 345                 return (v8plus_eventloop_rele_direct());
 346         }
 347 
 348         vac = calloc(1, sizeof (*vac));
 349         if (vac == NULL)
 350                 v8plus_panic("could not allocate async call structure");
 351 
 352         vac->vac_type = ACT_EVENTLOOP_RELEASE;
 353         vac->vac_flags = ACF_NOREPLY;
 354 
 355         (void) v8plus_cross_thread_call(vac);
 356 }
 357 
 358 nvlist_t *
 359 v8plus_verror(v8plus_errno_t e, const char *fmt, va_list ap)
 360 {
 361         if (fmt == NULL) {
 362                 if (e == V8PLUSERR_NOERROR) {
 363                         *_v8plus_errmsg = '\0';
 364                 } else {
 365                         (void) snprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN,
 366                             "%s", v8plus_strerror(e));
 367                 }
 368         } else {
 369                 (void) vsnprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN, fmt, ap);
 370         }
 371         _v8plus_errno = e;
 372 
 373         return (NULL);
 374 }
 375