Print this page
enable v8plus_call to be used in any thread
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 7 #include <sys/queue.h>
8 8 #include <sys/types.h>
9 9 #include <stdarg.h>
10 10 #include <string.h>
11 11 #include <strings.h>
12 12 #include <errno.h>
13 13 #include <uv.h>
14 14 #include <pthread.h>
15 15 #include "v8plus_glue.h"
16 16
17 17 __thread v8plus_errno_t _v8plus_errno;
18 18 __thread char _v8plus_errmsg[V8PLUS_ERRMSG_LEN];
19 19
20 20 typedef struct v8plus_uv_ctx {
21 21 void *vuc_obj;
22 22 void *vuc_ctx;
23 23 void *vuc_result;
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
24 24 v8plus_worker_f vuc_worker;
25 25 v8plus_completion_f vuc_completion;
26 26 } v8plus_uv_ctx_t;
27 27
28 28 static STAILQ_HEAD(v8plus_callq_head, v8plus_async_call) _v8plus_callq =
29 29 STAILQ_HEAD_INITIALIZER(_v8plus_callq);
30 30 static pthread_mutex_t _v8plus_callq_mtx;
31 31 static pthread_t _v8plus_uv_event_thread;
32 32 static uv_async_t _v8plus_uv_async;
33 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 +
34 41 typedef struct v8plus_async_call {
42 + v8plus_async_call_type_t vac_type;
43 + boolean_t vac_noreply;
44 +
45 + /*
46 + * For ACT_OBJECT_{CALL,RELEASE}:
47 + */
35 48 void *vac_cop;
36 49 const char *vac_name;
50 + /*
51 + * For ACT_JSFUNC_{CALL,RELEASE}:
52 + */
53 + v8plus_jsfunc_t vac_func;
54 +
55 + /*
56 + * Common call arguments:
57 + */
37 58 const nvlist_t *vac_lp;
38 59
39 60 pthread_cond_t vac_cv;
40 61 pthread_mutex_t vac_mtx;
41 62
42 63 boolean_t vac_run;
43 64 nvlist_t *vac_return;
44 65
45 66 STAILQ_ENTRY(v8plus_async_call) vac_callq_entry;
46 67 } v8plus_async_call_t;
47 68
48 69 boolean_t
49 70 v8plus_in_event_thread(void)
50 71 {
51 72 return (_v8plus_uv_event_thread == pthread_self() ? B_TRUE : B_FALSE);
52 73 }
53 74
54 75 static void
55 -v8plus_async_callback(uv_async_t *async, int status __UNUSED)
76 +v8plus_async_callback(uv_async_t *async __UNUSED, int status __UNUSED)
56 77 {
57 78 if (v8plus_in_event_thread() != B_TRUE)
58 79 v8plus_panic("async callback called outside of event loop");
59 80
60 81 for (;;) {
61 82 v8plus_async_call_t *vac = NULL;
62 83
63 84 /*
64 85 * Fetch the next queued method:
65 86 */
66 87 if (pthread_mutex_lock(&_v8plus_callq_mtx) != 0)
67 88 v8plus_panic("could not lock async queue mutex");
68 89 if (!STAILQ_EMPTY(&_v8plus_callq)) {
69 90 vac = STAILQ_FIRST(&_v8plus_callq);
70 91 STAILQ_REMOVE_HEAD(&_v8plus_callq, vac_callq_entry);
71 92 }
72 93 if (pthread_mutex_unlock(&_v8plus_callq_mtx) != 0)
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
73 94 v8plus_panic("could not unlock async queue mutex");
74 95
75 96 if (vac == NULL)
76 97 break;
77 98
78 99 /*
79 100 * Run the queued method:
80 101 */
81 102 if (vac->vac_run == B_TRUE)
82 103 v8plus_panic("async call already run");
83 - vac->vac_return = v8plus_method_call_direct(vac->vac_cop,
84 - vac->vac_name, vac->vac_lp);
104 +
105 + switch (vac->vac_type) {
106 + case ACT_OBJECT_CALL:
107 + vac->vac_return = v8plus_method_call_direct(
108 + vac->vac_cop, vac->vac_name, vac->vac_lp);
109 + break;
110 + case ACT_OBJECT_RELEASE:
111 + v8plus_obj_rele(vac->vac_cop);
112 + break;
113 + case ACT_JSFUNC_CALL:
114 + vac->vac_return = v8plus_call_direct(
115 + vac->vac_func, vac->vac_lp);
116 + break;
117 + case ACT_JSFUNC_RELEASE:
118 + v8plus_jsfunc_rele(vac->vac_func);
119 + break;
120 + }
121 +
122 + if (vac->vac_noreply == B_TRUE) {
123 + /*
124 + * The caller posted this event and is not sleeping
125 + * on a reply. Just free the call structure and move
126 + * on.
127 + */
128 + free(vac);
129 + if (vac->vac_lp != NULL)
130 + nvlist_free((nvlist_t *)vac->vac_lp);
131 + continue;
132 + }
85 133
86 134 if (pthread_mutex_lock(&vac->vac_mtx) != 0)
87 135 v8plus_panic("could not lock async call mutex");
88 136 vac->vac_run = B_TRUE;
89 137 if (pthread_cond_broadcast(&vac->vac_cv) != 0)
90 138 v8plus_panic("could not signal async call condvar");
91 139 if (pthread_mutex_unlock(&vac->vac_mtx) != 0)
92 140 v8plus_panic("could not unlock async call mutex");
93 141 }
94 142 }
95 143
96 -nvlist_t *
97 -v8plus_method_call(void *cop, const char *name, const nvlist_t *lp)
144 +/*
145 + * As we cannot manipulate v8plus/V8/Node structures directly from outside the
146 + * event loop thread, we push the call arguments onto a queue and post to the
147 + * event loop thread. We then sleep on our condition variable until the event
148 + * loop thread makes the call for us and wakes us up.
149 + *
150 + * This routine implements the parts of this interaction common to all
151 + * variants.
152 + */
153 +static nvlist_t *
154 +v8plus_cross_thread_call(v8plus_async_call_t *vac)
98 155 {
99 - v8plus_async_call_t vac;
100 -
101 - if (v8plus_in_event_thread() == B_TRUE) {
102 - /*
103 - * We're running in the event loop thread, so we can make the
104 - * call directly.
105 - */
106 - return (v8plus_method_call_direct(cop, name, lp));
107 - }
108 -
109 156 /*
110 - * As we cannot manipulate v8plus/V8/Node structures directly from
111 - * outside the event loop thread, we push the call arguments onto a
112 - * queue and post to the event loop thread. We then sleep on our
113 - * condition variable until the event loop thread makes the call
114 - * for us and wakes us up.
157 + * Common call structure initialisation:
115 158 */
116 - bzero(&vac, sizeof (vac));
117 - vac.vac_cop = cop;
118 - vac.vac_name = name;
119 - vac.vac_lp = lp;
120 - if (pthread_mutex_init(&vac.vac_mtx, NULL) != 0)
159 + if (pthread_mutex_init(&vac->vac_mtx, NULL) != 0)
121 160 v8plus_panic("could not init async call mutex");
122 - if (pthread_cond_init(&vac.vac_cv, NULL) != 0)
161 + if (pthread_cond_init(&vac->vac_cv, NULL) != 0)
123 162 v8plus_panic("could not init async call condvar");
124 - vac.vac_run = B_FALSE;
163 + vac->vac_run = B_FALSE;
125 164
126 165 /*
127 166 * Post request to queue:
128 167 */
129 168 if (pthread_mutex_lock(&_v8plus_callq_mtx) != 0)
130 169 v8plus_panic("could not lock async queue mutex");
131 - STAILQ_INSERT_TAIL(&_v8plus_callq, &vac, vac_callq_entry);
170 + STAILQ_INSERT_TAIL(&_v8plus_callq, vac, vac_callq_entry);
132 171 if (pthread_mutex_unlock(&_v8plus_callq_mtx) != 0)
133 172 v8plus_panic("could not unlock async queue mutex");
134 173 uv_async_send(&_v8plus_uv_async);
135 174
175 + if (vac->vac_noreply == B_TRUE) {
176 + /*
177 + * The caller does not care about the reply, and has allocated
178 + * the v8plus_async_call_t structure from the heap. The
179 + * async callback will free the storage when it completes.
180 + */
181 + return (NULL);
182 + }
183 +
136 184 /*
137 185 * Wait for our request to be serviced on the event loop thread:
138 186 */
139 - if (pthread_mutex_lock(&vac.vac_mtx) != 0)
187 + if (pthread_mutex_lock(&vac->vac_mtx) != 0)
140 188 v8plus_panic("could not lock async call mutex");
141 - while (vac.vac_run == B_FALSE) {
142 - if (pthread_cond_wait(&vac.vac_cv, &vac.vac_mtx) != 0)
189 + while (vac->vac_run == B_FALSE) {
190 + if (pthread_cond_wait(&vac->vac_cv, &vac->vac_mtx) != 0)
143 191 v8plus_panic("could not wait on async call condvar");
144 192 }
145 - if (pthread_mutex_unlock(&vac.vac_mtx) != 0)
193 + if (pthread_mutex_unlock(&vac->vac_mtx) != 0)
146 194 v8plus_panic("could not unlock async call mutex");
147 195
148 - if (pthread_cond_destroy(&vac.vac_cv) != 0)
196 + if (pthread_cond_destroy(&vac->vac_cv) != 0)
149 197 v8plus_panic("could not destroy async call condvar");
150 - if (pthread_mutex_destroy(&vac.vac_mtx) != 0)
198 + if (pthread_mutex_destroy(&vac->vac_mtx) != 0)
151 199 v8plus_panic("could not destroy async call mutex");
152 200
153 - return (vac.vac_return);
201 + return (vac->vac_return);
202 +}
203 +
204 +nvlist_t *
205 +v8plus_method_call(void *cop, const char *name, const nvlist_t *lp)
206 +{
207 + v8plus_async_call_t vac;
208 +
209 + if (v8plus_in_event_thread() == B_TRUE) {
210 + /*
211 + * We're running in the event loop thread, so we can make the
212 + * call directly.
213 + */
214 + return (v8plus_method_call_direct(cop, name, lp));
215 + }
216 +
217 + bzero(&vac, sizeof (vac));
218 + vac.vac_type = ACT_OBJECT_CALL;
219 + vac.vac_noreply = B_FALSE;
220 + vac.vac_cop = cop;
221 + vac.vac_name = name;
222 + vac.vac_lp = lp;
223 +
224 + return (v8plus_cross_thread_call(&vac));
225 +}
226 +
227 +nvlist_t *
228 +v8plus_call(v8plus_jsfunc_t func, const nvlist_t *lp)
229 +{
230 + v8plus_async_call_t vac;
231 +
232 + if (v8plus_in_event_thread() == B_TRUE) {
233 + /*
234 + * We're running in the event loop thread, so we can make the
235 + * call directly.
236 + */
237 + return (v8plus_call_direct(func, lp));
238 + }
239 +
240 + bzero(&vac, sizeof (vac));
241 + vac.vac_type = ACT_JSFUNC_CALL;
242 + vac.vac_noreply = B_FALSE;
243 + vac.vac_func = func;
244 + vac.vac_lp = lp;
245 +
246 + return (v8plus_cross_thread_call(&vac));
154 247 }
155 248
249 +void
250 +v8plus_obj_rele(const void *cop)
251 +{
252 + v8plus_async_call_t *vac;
253 +
254 + if (v8plus_in_event_thread() == B_TRUE) {
255 + return (v8plus_obj_rele_direct(cop));
256 + }
257 +
258 + vac = calloc(1, sizeof (*vac));
259 + if (vac == NULL)
260 + v8plus_panic("could not allocate async call structure");
261 +
262 + vac->vac_type = ACT_OBJECT_RELEASE;
263 + vac->vac_noreply = B_TRUE;
264 + vac->vac_cop = (void *)cop;
265 +
266 + (void) v8plus_cross_thread_call(vac);
267 +}
268 +
269 +void
270 +v8plus_jsfunc_rele(v8plus_jsfunc_t f)
271 +{
272 + v8plus_async_call_t *vac;
273 +
274 + if (v8plus_in_event_thread() == B_TRUE) {
275 + return (v8plus_jsfunc_rele_direct(f));
276 + }
277 +
278 + vac = calloc(1, sizeof (*vac));
279 + if (vac == NULL)
280 + v8plus_panic("could not allocate async call structure");
281 +
282 + vac->vac_type = ACT_JSFUNC_RELEASE;
283 + vac->vac_noreply = B_TRUE;
284 + vac->vac_func = f;
285 +
286 + (void) v8plus_cross_thread_call(vac);
287 +}
156 288
157 289 /*
158 290 * Initialise structures for off-event-loop method calls.
159 291 *
160 292 * Note that uv_async_init() must be called inside the libuv event loop, so we
161 293 * do it here. We also want to record the thread ID of the Event Loop thread
162 294 * so as to determine what kind of method calls to make later.
163 295 */
164 296 void
165 297 v8plus_crossthread_init(void)
166 298 {
167 299 _v8plus_uv_event_thread = pthread_self();
168 300 if (uv_async_init(uv_default_loop(), &_v8plus_uv_async,
169 301 v8plus_async_callback) != 0)
170 302 v8plus_panic("unable to initialise uv_async_t");
171 303 if (pthread_mutex_init(&_v8plus_callq_mtx, NULL) != 0)
172 304 v8plus_panic("unable to initialise mutex");
173 305 }
174 306
175 307 nvlist_t *
176 308 v8plus_verror(v8plus_errno_t e, const char *fmt, va_list ap)
177 309 {
178 310 if (fmt == NULL) {
179 311 if (e == V8PLUSERR_NOERROR) {
180 312 *_v8plus_errmsg = '\0';
181 313 } else {
182 314 (void) snprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN,
183 315 "%s", v8plus_strerror(e));
184 316 }
185 317 } else {
186 318 (void) vsnprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN, fmt, ap);
187 319 }
188 320 _v8plus_errno = e;
189 321
190 322 return (NULL);
191 323 }
192 324
193 325 nvlist_t *
194 326 v8plus_error(v8plus_errno_t e, const char *fmt, ...)
195 327 {
196 328 va_list ap;
197 329
198 330 va_start(ap, fmt);
199 331 (void) v8plus_verror(e, fmt, ap);
200 332 va_end(ap);
201 333
202 334 return (NULL);
203 335 }
204 336
205 337 static void __NORETURN
206 338 v8plus_vpanic(const char *fmt, va_list ap)
207 339 {
208 340 (void) vfprintf(stderr, fmt, ap);
209 341 (void) fflush(stderr);
210 342 abort();
211 343 }
212 344
213 345 void
214 346 v8plus_panic(const char *fmt, ...)
215 347 {
216 348 va_list ap;
217 349
218 350 va_start(ap, fmt);
219 351 v8plus_vpanic(fmt, ap);
220 352 va_end(ap);
221 353 }
222 354
223 355 nvlist_t *
224 356 v8plus_nverr(int nverr, const char *member)
225 357 {
226 358 (void) snprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN,
227 359 "nvlist manipulation error on member %s: %s",
228 360 member == NULL ? "<none>" : member, strerror(nverr));
229 361
230 362 switch (nverr) {
231 363 case ENOMEM:
232 364 _v8plus_errno = V8PLUSERR_NOMEM;
233 365 break;
234 366 case EINVAL:
235 367 _v8plus_errno = V8PLUSERR_YOUSUCK;
236 368 break;
237 369 default:
238 370 _v8plus_errno = V8PLUSERR_UNKNOWN;
239 371 break;
240 372 }
241 373
242 374 return (NULL);
243 375 }
244 376
245 377 nvlist_t *
246 378 v8plus_syserr(int syserr, const char *fmt, ...)
247 379 {
248 380 v8plus_errno_t e;
249 381 va_list ap;
250 382
251 383 switch (syserr) {
252 384 case ENOMEM:
253 385 e = V8PLUSERR_NOMEM;
254 386 break;
255 387 case EBADF:
256 388 e = V8PLUSERR_BADF;
257 389 break;
258 390 default:
259 391 e = V8PLUSERR_UNKNOWN;
260 392 break;
261 393 }
262 394
263 395 va_start(ap, fmt);
264 396 (void) v8plus_verror(e, fmt, ap);
265 397 va_end(ap);
266 398
267 399 return (NULL);
268 400 }
269 401
270 402 /*
271 403 * The NULL nvlist with V8PLUSERR_NOERROR means we are returning void.
272 404 */
273 405 nvlist_t *
274 406 v8plus_void(void)
275 407 {
276 408 return (v8plus_error(V8PLUSERR_NOERROR, NULL));
277 409 }
278 410
279 411 v8plus_type_t
280 412 v8plus_typeof(const nvpair_t *pp)
281 413 {
282 414 data_type_t t = nvpair_type((nvpair_t *)pp);
283 415
284 416 switch (t) {
285 417 case DATA_TYPE_DOUBLE:
286 418 return (V8PLUS_TYPE_NUMBER);
287 419 case DATA_TYPE_STRING:
288 420 return (V8PLUS_TYPE_STRING);
289 421 case DATA_TYPE_NVLIST:
290 422 return (V8PLUS_TYPE_OBJECT);
291 423 case DATA_TYPE_BOOLEAN_VALUE:
292 424 return (V8PLUS_TYPE_BOOLEAN);
293 425 case DATA_TYPE_BOOLEAN:
294 426 return (V8PLUS_TYPE_UNDEFINED);
295 427 case DATA_TYPE_BYTE:
296 428 {
297 429 uchar_t v;
298 430 if (nvpair_value_byte((nvpair_t *)pp, &v) != 0 || v != 0)
299 431 return (V8PLUS_TYPE_INVALID);
300 432 return (V8PLUS_TYPE_NULL);
301 433 }
302 434 case DATA_TYPE_UINT64_ARRAY:
303 435 {
304 436 uint64_t *vp;
305 437 uint_t nv;
306 438 if (nvpair_value_uint64_array((nvpair_t *)pp, &vp, &nv) != 0 ||
307 439 nv != 1) {
308 440 return (V8PLUS_TYPE_INVALID);
309 441 }
310 442 return (V8PLUS_TYPE_JSFUNC);
311 443 }
312 444 default:
313 445 return (V8PLUS_TYPE_INVALID);
314 446 }
315 447 }
316 448
317 449 static int
318 450 v8plus_arg_value(v8plus_type_t t, const nvpair_t *pp, void *vp)
319 451 {
320 452 data_type_t dt = nvpair_type((nvpair_t *)pp);
321 453
322 454 switch (t) {
323 455 case V8PLUS_TYPE_NONE:
324 456 return (-1);
325 457 case V8PLUS_TYPE_STRING:
326 458 if (dt == DATA_TYPE_STRING) {
327 459 if (vp != NULL) {
328 460 (void) nvpair_value_string((nvpair_t *)pp,
329 461 (char **)vp);
330 462 }
331 463 return (0);
332 464 }
333 465 return (-1);
334 466 case V8PLUS_TYPE_NUMBER:
335 467 if (dt == DATA_TYPE_DOUBLE) {
336 468 if (vp != NULL) {
337 469 (void) nvpair_value_double((nvpair_t *)pp,
338 470 (double *)vp);
339 471 }
340 472 return (0);
341 473 }
342 474 return (-1);
343 475 case V8PLUS_TYPE_BOOLEAN:
344 476 if (dt == DATA_TYPE_BOOLEAN_VALUE) {
345 477 if (vp != NULL) {
346 478 (void) nvpair_value_boolean_value(
347 479 (nvpair_t *)pp, (boolean_t *)vp);
348 480 }
349 481 return (0);
350 482 }
351 483 return (-1);
352 484 case V8PLUS_TYPE_JSFUNC:
353 485 if (dt == DATA_TYPE_UINT64_ARRAY) {
354 486 uint_t nv;
355 487 uint64_t *vpp;
356 488
357 489 if (nvpair_value_uint64_array((nvpair_t *)pp,
358 490 &vpp, &nv) == 0 && nv == 1) {
359 491 if (vp != NULL)
360 492 *(v8plus_jsfunc_t *)vp = vpp[0];
361 493 return (0);
362 494 }
363 495 }
364 496 return (-1);
365 497 case V8PLUS_TYPE_OBJECT:
366 498 if (dt == DATA_TYPE_NVLIST) {
367 499 if (vp != NULL) {
368 500 (void) nvpair_value_nvlist((nvpair_t *)pp,
369 501 (nvlist_t **)vp);
370 502 }
371 503 return (0);
372 504 }
373 505 return (-1);
374 506 case V8PLUS_TYPE_NULL:
375 507 if (dt == DATA_TYPE_BYTE) {
376 508 uchar_t v;
377 509
378 510 if (nvpair_value_byte((nvpair_t *)pp, &v) == 0 &&
379 511 v == 0)
380 512 return (0);
381 513 }
382 514 return (-1);
383 515 case V8PLUS_TYPE_UNDEFINED:
384 516 return (dt == DATA_TYPE_BOOLEAN ? 0 : -1);
385 517 case V8PLUS_TYPE_ANY:
386 518 if (vp != NULL)
387 519 *(const nvpair_t **)vp = pp;
388 520 return (0);
389 521 case V8PLUS_TYPE_INVALID:
390 522 if (vp != NULL)
391 523 *(data_type_t *)vp = dt;
392 524 return (0);
393 525 case V8PLUS_TYPE_STRNUMBER64:
394 526 if (dt == DATA_TYPE_STRING) {
395 527 char *s;
396 528 uint64_t v;
397 529
398 530 (void) nvpair_value_string((nvpair_t *)pp, &s);
399 531 errno = 0;
400 532 v = (uint64_t)strtoull(s, NULL, 0);
401 533 if (errno != 0)
402 534 return (-1);
403 535 if (vp != NULL)
404 536 *(uint64_t *)vp = v;
405 537 return (0);
406 538 }
407 539 return (-1);
408 540 default:
409 541 return (-1);
410 542 }
411 543 }
412 544
413 545 int
414 546 v8plus_args(const nvlist_t *lp, uint_t flags, v8plus_type_t t, ...)
415 547 {
416 548 v8plus_type_t nt;
417 549 nvpair_t *pp;
418 550 void *vp;
419 551 va_list ap;
420 552 uint_t i;
421 553 char buf[32];
422 554
423 555 va_start(ap, t);
424 556
425 557 for (i = 0, nt = t; nt != V8PLUS_TYPE_NONE; i++) {
426 558 switch (nt) {
427 559 case V8PLUS_TYPE_UNDEFINED:
428 560 case V8PLUS_TYPE_NULL:
429 561 break;
430 562 default:
431 563 (void) va_arg(ap, void *);
432 564 }
433 565
434 566 (void) snprintf(buf, sizeof (buf), "%u", i);
435 567 if (nvlist_lookup_nvpair((nvlist_t *)lp, buf, &pp) != 0) {
436 568 (void) v8plus_error(V8PLUSERR_MISSINGARG,
437 569 "argument %u is required", i);
438 570 return (-1);
439 571 }
440 572
441 573 if (v8plus_arg_value(nt, pp, NULL) != 0) {
442 574 (void) v8plus_error(V8PLUSERR_BADARG,
443 575 "argument %u is of incorrect type", i);
444 576 return (-1);
445 577 }
446 578
447 579 nt = va_arg(ap, data_type_t);
448 580 }
449 581
450 582 va_end(ap);
451 583
452 584 if (flags & V8PLUS_ARG_F_NOEXTRA) {
453 585 (void) snprintf(buf, sizeof (buf), "%u", i);
454 586 if (nvlist_lookup_nvpair((nvlist_t *)lp, buf, &pp) == 0) {
455 587 (void) v8plus_error(V8PLUSERR_EXTRAARG,
456 588 "superfluous extra argument(s) detected");
457 589 return (-1);
458 590 }
459 591 }
460 592
461 593 va_start(ap, t);
462 594
463 595 for (i = 0, nt = t; nt != V8PLUS_TYPE_NONE; i++) {
464 596 switch (nt) {
465 597 case V8PLUS_TYPE_UNDEFINED:
466 598 case V8PLUS_TYPE_NULL:
467 599 vp = NULL;
468 600 break;
469 601 default:
470 602 vp = va_arg(ap, void *);
471 603 }
472 604
473 605 (void) snprintf(buf, sizeof (buf), "%u", i);
474 606 VERIFY(nvlist_lookup_nvpair((nvlist_t *)lp, buf, &pp) == 0);
475 607 VERIFY(v8plus_arg_value(nt, pp, vp) == 0);
476 608
477 609 nt = va_arg(ap, data_type_t);
478 610 }
479 611
480 612 va_end(ap);
481 613
482 614 return (0);
483 615 }
484 616
485 617 static int
486 618 v8plus_obj_vsetprops(nvlist_t *lp, v8plus_type_t t, va_list *ap)
487 619 {
488 620 v8plus_type_t nt = t;
489 621 char *name;
490 622 int err;
491 623
492 624 /*
493 625 * Do not call va_start() or va_end() in this function! We are limited
494 626 * to a single traversal of the arguments so that we can recurse to
495 627 * handle embedded object definitions.
496 628 */
497 629
498 630 while (nt != V8PLUS_TYPE_NONE) {
499 631 name = va_arg(*ap, char *);
500 632
501 633 switch (nt) {
502 634 case V8PLUS_TYPE_STRING:
503 635 {
504 636 char *s = va_arg(*ap, char *);
505 637 if ((err = nvlist_add_string(lp, name, s)) != 0) {
506 638 (void) v8plus_nverr(err, name);
507 639 return (-1);
508 640 }
509 641 break;
510 642 }
511 643 case V8PLUS_TYPE_NUMBER:
512 644 {
513 645 double d = va_arg(*ap, double);
514 646 if ((err = nvlist_add_double(lp, name, d)) != 0) {
515 647 (void) v8plus_nverr(err, name);
516 648 return (-1);
517 649 }
518 650 break;
519 651 }
520 652 case V8PLUS_TYPE_BOOLEAN:
521 653 {
522 654 boolean_t b = va_arg(*ap, boolean_t);
523 655 if ((err = nvlist_add_boolean_value(lp,
524 656 name, b)) != 0) {
525 657 (void) v8plus_nverr(err, name);
526 658 return (-1);
527 659 }
528 660 break;
529 661 }
530 662 case V8PLUS_TYPE_JSFUNC:
531 663 {
532 664 v8plus_jsfunc_t j = va_arg(*ap, v8plus_jsfunc_t);
533 665 if ((err = nvlist_add_uint64_array(lp,
534 666 name, &j, 1)) != 0) {
535 667 (void) v8plus_nverr(err, name);
536 668 return (-1);
537 669 }
538 670 if ((err = nvlist_add_string_array(lp,
539 671 V8PLUS_JSF_COOKIE, NULL, 0)) != 0) {
540 672 (void) v8plus_nverr(err, V8PLUS_JSF_COOKIE);
541 673 return (-1);
542 674 }
543 675 v8plus_jsfunc_hold(j);
544 676 break;
545 677 }
546 678 case V8PLUS_TYPE_OBJECT:
547 679 {
548 680 const nvlist_t *op = va_arg(*ap, const nvlist_t *);
549 681 if ((err = nvlist_add_nvlist(lp, name,
550 682 (nvlist_t *)op)) != 0) {
551 683 (void) v8plus_nverr(err, name);
552 684 return (-1);
553 685 }
554 686 break;
555 687 }
556 688 case V8PLUS_TYPE_NULL:
557 689 if ((err = nvlist_add_byte(lp, name, 0)) != 0) {
558 690 (void) v8plus_nverr(err, name);
559 691 return (-1);
560 692 }
561 693 break;
562 694 case V8PLUS_TYPE_UNDEFINED:
563 695 if ((err = nvlist_add_boolean(lp, name)) != 0) {
564 696 (void) v8plus_nverr(err, name);
565 697 return (-1);
566 698 }
567 699 break;
568 700 case V8PLUS_TYPE_ANY:
569 701 {
570 702 nvpair_t *pp = va_arg(*ap, nvpair_t *);
571 703 if ((err = nvlist_add_nvpair(lp, pp)) != 0) {
572 704 (void) v8plus_nverr(err, name);
573 705 return (-1);
574 706 }
575 707 break;
576 708 }
577 709 case V8PLUS_TYPE_STRNUMBER64:
578 710 {
579 711 uint64_t v = va_arg(*ap, uint64_t);
580 712 char s[32];
581 713 (void) snprintf(s, sizeof (s), "%" PRIu64, v);
582 714 if ((err = nvlist_add_string(lp, name, s)) != 0) {
583 715 (void) v8plus_nverr(err, name);
584 716 return (-1);
585 717 }
586 718 break;
587 719 }
588 720 case V8PLUS_TYPE_INL_OBJECT:
589 721 {
590 722 nvlist_t *slp;
591 723
592 724 nt = va_arg(*ap, v8plus_type_t);
593 725 err = nvlist_alloc(&slp, NV_UNIQUE_NAME, 0);
594 726 if (err != 0) {
595 727 (void) v8plus_nverr(err, name);
596 728 return (-1);
597 729 }
598 730 if (v8plus_obj_vsetprops(slp, nt, ap) != 0)
599 731 return (-1);
600 732
601 733 err = nvlist_add_nvlist(lp, name, slp);
602 734 nvlist_free(slp);
603 735 if (err != 0) {
604 736 (void) v8plus_nverr(err, name);
605 737 return (-1);
606 738 }
607 739 break;
608 740 }
609 741 case V8PLUS_TYPE_INVALID:
610 742 default:
611 743 (void) v8plus_error(V8PLUSERR_YOUSUCK,
612 744 "invalid property type %d", nt);
613 745 return (-1);
614 746 }
615 747
616 748 nt = va_arg(*ap, v8plus_type_t);
617 749 }
618 750
619 751 return (0);
620 752 }
621 753
622 754 nvlist_t *
623 755 v8plus_obj(v8plus_type_t t, ...)
624 756 {
625 757 nvlist_t *rp;
626 758 va_list ap;
627 759 int err;
628 760
629 761 if ((err = nvlist_alloc(&rp, NV_UNIQUE_NAME, 0)) != 0)
630 762 return (v8plus_nverr(err, NULL));
631 763
632 764 va_start(ap, t);
633 765 err = v8plus_obj_vsetprops(rp, t, &ap);
634 766 va_end(ap);
635 767
636 768 if (err != 0) {
637 769 nvlist_free(rp);
638 770 rp = NULL;
639 771 }
640 772
641 773 return (rp);
642 774 }
643 775
644 776 int
645 777 v8plus_obj_setprops(nvlist_t *lp, v8plus_type_t t, ...)
646 778 {
647 779 va_list ap;
648 780 int err;
649 781
650 782 va_start(ap, t);
651 783 err = v8plus_obj_vsetprops(lp, t, &ap);
652 784 va_end(ap);
653 785
654 786 return (err);
655 787 }
656 788
657 789 static void
658 790 v8plus_uv_worker(uv_work_t *wp)
659 791 {
660 792 v8plus_uv_ctx_t *cp = wp->data;
661 793
662 794 cp->vuc_result = cp->vuc_worker(cp->vuc_obj, cp->vuc_ctx);
663 795 }
664 796
665 797 static void
666 798 v8plus_uv_completion(uv_work_t *wp)
667 799 {
668 800 v8plus_uv_ctx_t *cp = wp->data;
669 801
670 802 cp->vuc_completion(cp->vuc_obj, cp->vuc_ctx, cp->vuc_result);
671 803 v8plus_obj_rele(cp->vuc_obj);
672 804 free(cp);
673 805 free(wp);
674 806 }
675 807
676 808 void
677 809 v8plus_defer(void *cop, void *ctxp, v8plus_worker_f worker,
678 810 v8plus_completion_f completion)
679 811 {
680 812 uv_work_t *wp = malloc(sizeof (uv_work_t));
681 813 v8plus_uv_ctx_t *cp = malloc(sizeof (v8plus_uv_ctx_t));
682 814
683 815 bzero(wp, sizeof (uv_work_t));
684 816 bzero(cp, sizeof (v8plus_uv_ctx_t));
685 817
686 818 v8plus_obj_hold(cop);
687 819 cp->vuc_obj = cop;
688 820 cp->vuc_ctx = ctxp;
689 821 cp->vuc_worker = worker;
690 822 cp->vuc_completion = completion;
691 823 wp->data = cp;
692 824
693 825 uv_queue_work(uv_default_loop(), wp, v8plus_uv_worker,
694 826 v8plus_uv_completion);
695 827 }
↓ open down ↓ |
530 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX