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