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, ...)
|