Print this page
XXX review feedback from keith

Split Close
Expand all
Collapse all
          --- old/./v8plus_csup.c
          +++ new/./v8plus_csup.c
   1    1  /*
   2    2   * Copyright (c) 2012 Joyent, Inc.  All rights reserved.
   3    3   */
   4    4  
   5    5  #include <sys/ccompile.h>
   6    6  #include <sys/debug.h>
        7 +#include <sys/queue.h>
        8 +#include <sys/types.h>
   7    9  #include <stdarg.h>
   8   10  #include <string.h>
   9   11  #include <strings.h>
  10   12  #include <errno.h>
  11   13  #include <uv.h>
       14 +#include <pthread.h>
  12   15  #include "v8plus_glue.h"
  13   16  
  14   17  __thread v8plus_errno_t _v8plus_errno;
  15   18  __thread char _v8plus_errmsg[V8PLUS_ERRMSG_LEN];
  16   19  
  17   20  typedef struct v8plus_uv_ctx {
  18   21          void *vuc_obj;
  19   22          void *vuc_ctx;
  20   23          void *vuc_result;
  21   24          v8plus_worker_f vuc_worker;
  22   25          v8plus_completion_f vuc_completion;
  23   26  } v8plus_uv_ctx_t;
  24   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 struct v8plus_async_call {
       35 +        void *vac_cop;
       36 +        const char *vac_name;
       37 +        const nvlist_t *vac_lp;
       38 +
       39 +        pthread_cond_t vac_cv;
       40 +        pthread_mutex_t vac_mtx;
       41 +
       42 +        boolean_t vac_run;
       43 +        nvlist_t *vac_return;
       44 +
       45 +        STAILQ_ENTRY(v8plus_async_call) vac_callq_entry;
       46 +} v8plus_async_call_t;
       47 +
       48 +nvlist_t *v8plus_method_call_direct(void *, const char *, const nvlist_t *);
       49 +
       50 +boolean_t
       51 +v8plus_in_event_thread(void)
       52 +{
       53 +        return (_v8plus_uv_event_thread == pthread_self() ? B_TRUE : B_FALSE);
       54 +}
       55 +
       56 +static void
       57 +v8plus_async_callback(uv_async_t *async, __attribute__((unused)) int status)
       58 +{
       59 +        if (v8plus_in_event_thread() != B_TRUE)
       60 +                v8plus_panic("async callback called outside of event loop");
       61 +
       62 +        for (;;) {
       63 +                v8plus_async_call_t *vac = NULL;
       64 +
       65 +                /*
       66 +                 * Fetch the next queued method:
       67 +                 */
       68 +                if (pthread_mutex_lock(&_v8plus_callq_mtx) != 0)
       69 +                        v8plus_panic("could not lock async queue mutex");
       70 +                if (!STAILQ_EMPTY(&_v8plus_callq)) {
       71 +                        vac = STAILQ_FIRST(&_v8plus_callq);
       72 +                        STAILQ_REMOVE_HEAD(&_v8plus_callq, vac_callq_entry);
       73 +                }
       74 +                if (pthread_mutex_unlock(&_v8plus_callq_mtx) != 0)
       75 +                        v8plus_panic("could not unlock async queue mutex");
       76 +
       77 +                if (vac == NULL)
       78 +                        break;
       79 +
       80 +                /*
       81 +                 * Run the queued method:
       82 +                 */
       83 +                if (pthread_mutex_lock(&vac->vac_mtx) != 0)
       84 +                        v8plus_panic("could not lock async call mutex");
       85 +
       86 +                if (vac->vac_run == B_TRUE)
       87 +                        v8plus_panic("async call already run");
       88 +
       89 +                vac->vac_return = v8plus_method_call_direct(vac->vac_cop,
       90 +                    vac->vac_name, vac->vac_lp);
       91 +                vac->vac_run = B_TRUE;
       92 +
       93 +                if (pthread_cond_broadcast(&vac->vac_cv) != 0)
       94 +                        v8plus_panic("could not signal async call condvar");
       95 +                if (pthread_mutex_unlock(&vac->vac_mtx) != 0)
       96 +                        v8plus_panic("could not unlock async call mutex");
       97 +        }
       98 +}
       99 +
      100 +nvlist_t *
      101 +v8plus_method_call(void *cop, const char *name, const nvlist_t *lp)
      102 +{
      103 +        v8plus_async_call_t vac;
      104 +
      105 +        if (v8plus_in_event_thread() == B_TRUE) {
      106 +                /*
      107 +                 * We're running in the event loop thread, so we can make the
      108 +                 * call directly.
      109 +                 */
      110 +                return (v8plus_method_call_direct(cop, name, lp));
      111 +        }
      112 +
      113 +        /*
      114 +         * As we cannot manipulate v8plus/V8/Node structures directly from
      115 +         * outside the event loop thread, we push the call arguments onto a
      116 +         * queue and post to the event loop thread.  We then sleep on our
      117 +         * condition variable until the event loop thread makes the call
      118 +         * for us and wakes us up.
      119 +         */
      120 +        vac.vac_cop = cop;
      121 +        vac.vac_name = name;
      122 +        vac.vac_lp = lp;
      123 +        if (pthread_mutex_init(&vac.vac_mtx, NULL) != 0)
      124 +                v8plus_panic("could not init async call mutex");
      125 +        if (pthread_cond_init(&vac.vac_cv, NULL) != 0)
      126 +                v8plus_panic("could not init async call condvar");
      127 +        vac.vac_run = B_FALSE;
      128 +        vac.vac_return = NULL;
      129 +
      130 +        /*
      131 +         * Post request to queue:
      132 +         */
      133 +        if (pthread_mutex_lock(&_v8plus_callq_mtx) != 0)
      134 +                v8plus_panic("could not lock async queue mutex");
      135 +        STAILQ_INSERT_TAIL(&_v8plus_callq, &vac, vac_callq_entry);
      136 +        if (pthread_mutex_unlock(&_v8plus_callq_mtx) != 0)
      137 +                v8plus_panic("could not unlock async queue mutex");
      138 +        uv_async_send(&_v8plus_uv_async);
      139 +
      140 +        /*
      141 +         * Wait for our request to be serviced on the Event Loop thread:
      142 +         */
      143 +        if (pthread_mutex_lock(&vac.vac_mtx) != 0)
      144 +                v8plus_panic("could not lock async call mutex");
      145 +        while (vac.vac_run == B_FALSE) {
      146 +                if (pthread_cond_wait(&vac.vac_cv, &vac.vac_mtx) != 0)
      147 +                        v8plus_panic("could not wait on async call condvar");
      148 +        }
      149 +
      150 +        return (vac.vac_return);
      151 +}
      152 +
      153 +
      154 +/*
      155 + * Initialise structures for off-event-loop method calls.
      156 + *
      157 + * Note that uv_async_init() must be called inside the libuv Event Loop, so we
      158 + * do it here.  We also want to record the thread ID of the Event Loop thread
      159 + * so as to determine what kind of method calls to make later.
      160 + */
      161 +void
      162 +v8plus_crossthread_init(void)
      163 +{
      164 +        _v8plus_uv_event_thread = pthread_self();
      165 +        if (uv_async_init(uv_default_loop(), &_v8plus_uv_async,
      166 +            v8plus_async_callback) != 0)
      167 +                v8plus_panic("unable to initialise uv_async_t");
      168 +        if (pthread_mutex_init(&_v8plus_callq_mtx, NULL) != 0)
      169 +                v8plus_panic("unable to initialise mutex");
      170 +}
      171 +
  25  172  nvlist_t *
  26  173  v8plus_verror(v8plus_errno_t e, const char *fmt, va_list ap)
  27  174  {
  28  175          if (fmt == NULL) {
  29  176                  if (e == V8PLUSERR_NOERROR) {
  30  177                          *_v8plus_errmsg = '\0';
  31  178                  } else {
  32  179                          (void) snprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN,
  33  180                              "%s", v8plus_strerror(e));
  34  181                  }
↓ open down ↓ 511 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX