Print this page
XXX review feedback from keith
   1 /*
   2  * Copyright (c) 2012 Joyent, Inc.  All rights reserved.
   3  */
   4 
   5 #include <sys/ccompile.h>
   6 #include <sys/debug.h>


   7 #include <stdarg.h>
   8 #include <string.h>
   9 #include <strings.h>
  10 #include <errno.h>
  11 #include <uv.h>

  12 #include "v8plus_glue.h"
  13 
  14 __thread v8plus_errno_t _v8plus_errno;
  15 __thread char _v8plus_errmsg[V8PLUS_ERRMSG_LEN];
  16 
  17 typedef struct v8plus_uv_ctx {
  18         void *vuc_obj;
  19         void *vuc_ctx;
  20         void *vuc_result;
  21         v8plus_worker_f vuc_worker;
  22         v8plus_completion_f vuc_completion;
  23 } v8plus_uv_ctx_t;
  24 
















































































































































  25 nvlist_t *
  26 v8plus_verror(v8plus_errno_t e, const char *fmt, va_list ap)
  27 {
  28         if (fmt == NULL) {
  29                 if (e == V8PLUSERR_NOERROR) {
  30                         *_v8plus_errmsg = '\0';
  31                 } else {
  32                         (void) snprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN,
  33                             "%s", v8plus_strerror(e));
  34                 }
  35         } else {
  36                 (void) vsnprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN, fmt, ap);
  37         }
  38         _v8plus_errno = e;
  39 
  40         return (NULL);
  41 }
  42 
  43 nvlist_t *
  44 v8plus_error(v8plus_errno_t e, const char *fmt, ...)


   1 /*
   2  * Copyright (c) 2012 Joyent, Inc.  All rights reserved.
   3  */
   4 
   5 #include <sys/ccompile.h>
   6 #include <sys/debug.h>
   7 #include <sys/queue.h>
   8 #include <sys/types.h>
   9 #include <stdarg.h>
  10 #include <string.h>
  11 #include <strings.h>
  12 #include <errno.h>
  13 #include <uv.h>
  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 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 
 172 nvlist_t *
 173 v8plus_verror(v8plus_errno_t e, const char *fmt, va_list ap)
 174 {
 175         if (fmt == NULL) {
 176                 if (e == V8PLUSERR_NOERROR) {
 177                         *_v8plus_errmsg = '\0';
 178                 } else {
 179                         (void) snprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN,
 180                             "%s", v8plus_strerror(e));
 181                 }
 182         } else {
 183                 (void) vsnprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN, fmt, ap);
 184         }
 185         _v8plus_errno = e;
 186 
 187         return (NULL);
 188 }
 189 
 190 nvlist_t *
 191 v8plus_error(v8plus_errno_t e, const char *fmt, ...)