Print this page
joyent/v8plus#7 v8plus should not hold the event loop open forever
Split |
Close |
Expand all |
Collapse all |
--- old/./v8plus_subr.cc
+++ new/./v8plus_subr.cc
1 1 /*
2 2 * Copyright (c) 2012 Joyent, Inc. All rights reserved.
3 3 */
4 4
5 5 #include <sys/types.h>
6 6 #include <stdarg.h>
7 7 #include <stdlib.h>
8 8 #include <string.h>
9 9 #include <alloca.h>
10 10 #include <dlfcn.h>
11 11 #include <libnvpair.h>
12 12 #include <node.h>
13 13 #include <v8.h>
14 14 #include <unordered_map>
15 15 #include <string>
16 16 #include "v8plus_impl.h"
17 17
18 18 #define V8PLUS_OBJ_TYPE_MEMBER ".__v8plus_type"
19 19 #define V8_EXCEPTION_CTOR_FMT \
20 20 "_ZN2v89Exception%u%sENS_6HandleINS_6StringEEE"
21 21
22 22 typedef struct cb_hdl {
23 23 v8::Handle<v8::Function> ch_hdl;
24 24 uint_t ch_refs;
25 25 boolean_t ch_persist;
26 26 } cb_hdl_t;
27 27
28 28 static std::unordered_map<uint64_t, cb_hdl_t> cbhash;
29 29 static uint64_t cbnext;
30 30 static void (*__real_nvlist_free)(nvlist_t *);
31 31
32 32 static const char *
33 33 cstr(const v8::String::Utf8Value &v)
34 34 {
35 35 return (*v);
36 36 }
37 37
38 38 /*
39 39 * Convenience macros for adding stuff to an nvlist and returning on failure.
40 40 */
41 41 #define LA_U(_l, _n, _e) \
42 42 if (((_e) = nvlist_add_boolean((_l), (_n))) != 0) \
43 43 return (_e)
44 44
45 45 #define LA_N(_l, _n, _e) \
46 46 if (((_e) = nvlist_add_byte((_l), (_n), 0)) != 0) \
47 47 return (_e)
48 48
49 49 #define LA_V(_l, _t, _n, _v, _e) \
50 50 if (((_e) = nvlist_add_##_t((_l), (_n), (_v))) != 0) \
51 51 return (_e)
52 52
53 53 #define LA_VA(_l, _t, _n, _v, _c, _e) \
54 54 if (((_e) = nvlist_add_##_t##_array((_l), (_n), (_v), (_c))) != 0) \
55 55 return (_e)
56 56
57 57 /*
58 58 * Add an element named <name> to list <lp> with a transcoded value
59 59 * corresponding to <vh> if possible. Only primitive types, objects that are
60 60 * thin wrappers for primitive types, and objects containing members whose
61 61 * types are all any of the above can be transcoded.
62 62 *
63 63 * Booleans and their Object type are encoded as boolean_value.
64 64 * Numbers and their Object type are encoded as double.
65 65 * Strings and their Object type are encoded as C strings (and assumed UTF-8).
66 66 * Any Object (including an Array) is encoded as an nvlist whose elements
67 67 * are the Object's own properties.
68 68 * Null is encoded as a byte with value 0.
69 69 * Undefined is encoded as the valueless boolean.
70 70 *
71 71 * Returns EINVAL if any argument fails these tests, or any other error code
72 72 * that may be returned by nvlist_add_XXX(3nvpair).
73 73 */
74 74 static int
75 75 nvlist_add_v8_Value(nvlist_t *lp, const char *name,
76 76 const v8::Handle<v8::Value> &vh)
77 77 {
78 78 int err = 0;
79 79
80 80 if (vh->IsBoolean()) {
81 81 boolean_t vv = vh->BooleanValue() ? _B_TRUE : _B_FALSE;
82 82 LA_V(lp, boolean_value, name, vv, err);
83 83 } else if (vh->IsNumber()) {
84 84 double vv = vh->NumberValue();
85 85 LA_V(lp, double, name, vv, err);
86 86 } else if (vh->IsString()) {
87 87 v8::String::Utf8Value s(vh);
88 88 const char *vv = cstr(s);
89 89 LA_V(lp, string, name, vv, err);
90 90 } else if (vh->IsUndefined()) {
91 91 LA_U(lp, name, err);
92 92 } else if (vh->IsNull()) {
93 93 LA_N(lp, name, err);
94 94 } else if (vh->IsNumberObject()) {
95 95 double vv = vh->NumberValue();
96 96 LA_V(lp, double, name, vv, err);
97 97 } else if (vh->IsStringObject()) {
98 98 v8::String::Utf8Value s(vh);
99 99 const char *vv = cstr(s);
100 100 LA_V(lp, string, name, vv, err);
101 101 } else if (vh->IsBooleanObject()) {
102 102 boolean_t vv = vh->BooleanValue() ? _B_TRUE : _B_FALSE;
103 103 LA_V(lp, boolean_value, name, vv, err);
104 104 } else if (vh->IsFunction()) {
105 105 cb_hdl_t ch;
106 106
107 107 ch.ch_hdl = v8::Handle<v8::Function>::Cast(vh);
108 108 ch.ch_refs = 1;
109 109 ch.ch_persist = _B_FALSE;
110 110
111 111 while (cbhash.find(cbnext) != cbhash.end())
112 112 ++cbnext;
113 113 cbhash.insert(std::make_pair(cbnext, ch));
114 114
115 115 LA_VA(lp, string, V8PLUS_JSF_COOKIE, NULL, 0, err);
116 116 LA_VA(lp, uint64, name, &cbnext, 1, err);
117 117 } else if (vh->IsObject()) {
118 118 v8::Local<v8::Object> oh = vh->ToObject();
119 119 v8::Local<v8::Array> keys = oh->GetOwnPropertyNames();
120 120 v8::Local<v8::String> th = oh->GetConstructorName();
121 121 v8::String::Utf8Value tv(th);
122 122 const char *type = cstr(tv);
123 123 nvlist_t *vlp;
124 124 uint_t i;
125 125
126 126 if ((err = nvlist_alloc(&vlp, NV_UNIQUE_NAME, 0)) != 0)
127 127 return (err);
128 128
129 129 /* XXX this is vile; can we handle this generally? */
130 130 if (strcmp(type, "Object") != 0) {
131 131 if (strcmp(type, "Array") == 0) {
132 132 if ((err = nvlist_add_string(vlp,
133 133 V8PLUS_OBJ_TYPE_MEMBER, type)) != 0) {
134 134 nvlist_free(vlp);
135 135 return (err);
136 136 }
137 137 } else {
138 138 /*
139 139 * XXX This is (C) programmer error. Should
140 140 * we plumb up a way to throw here?
141 141 */
142 142 (void) v8plus_panic("can't handle %s", type);
143 143 }
144 144 }
145 145
146 146 for (i = 0; i < keys->Length(); i++) {
147 147 char knname[16];
148 148 v8::Local<v8::Value> mk;
149 149 v8::Local<v8::Value> mv;
150 150 const char *k;
151 151
152 152 (void) snprintf(knname, sizeof (knname), "%u", i);
153 153 mk = keys->Get(v8::String::New(knname));
154 154 mv = oh->Get(mk);
155 155 v8::String::Utf8Value mks(mk);
156 156 k = cstr(mks);
157 157
158 158 if ((err = nvlist_add_v8_Value(vlp, k, mv)) != 0) {
159 159 nvlist_free(vlp);
160 160 return (err);
161 161 }
162 162 }
163 163
164 164 LA_V(lp, nvlist, name, vlp, err);
165 165 } else {
166 166 return (EINVAL);
167 167 }
168 168
169 169 return (0);
170 170 }
171 171
172 172 #undef LA_U
173 173 #undef LA_N
174 174 #undef LA_V
175 175
176 176 nvlist_t *
177 177 v8plus::v8_Arguments_to_nvlist(const v8::Arguments &args)
178 178 {
179 179 char name[16];
180 180 nvlist_t *lp;
181 181 int err;
182 182 uint_t i;
183 183
184 184 if ((err = nvlist_alloc(&lp, NV_UNIQUE_NAME, 0)) != 0)
185 185 return (v8plus_nverr(err, NULL));
186 186
187 187 for (i = 0; i < (uint_t)args.Length(); i++) {
188 188 (void) snprintf(name, sizeof (name), "%u", i);
189 189 if ((err = nvlist_add_v8_Value(lp, name, args[i])) != 0) {
190 190 nvlist_free(lp);
191 191 return (v8plus_nverr(err, name));
192 192 }
193 193 }
194 194
195 195 return (lp);
196 196 }
197 197
198 198 static void
199 199 decorate_object(v8::Local<v8::Object> &oh, const nvlist_t *lp)
200 200 {
201 201 nvpair_t *pp = NULL;
202 202
203 203 while ((pp =
204 204 nvlist_next_nvpair(const_cast<nvlist_t *>(lp), pp)) != NULL) {
205 205 oh->Set(v8::String::New(nvpair_name(pp)),
206 206 v8plus::nvpair_to_v8_Value(pp));
207 207 }
208 208 }
209 209
210 210 #define RETURN_JS(_p, _jt, _ct, _xt, _pt) \
211 211 do { \
212 212 _ct _v; \
213 213 (void) nvpair_value_##_pt(const_cast<nvpair_t *>(_p), &_v); \
214 214 return (v8::_jt::New((_xt)_v)); \
215 215 } while (0)
216 216
217 217 v8::Handle<v8::Value>
218 218 v8plus::nvpair_to_v8_Value(const nvpair_t *pp)
219 219 {
220 220 const char *type;
221 221
222 222 switch (nvpair_type(const_cast<nvpair_t *>(pp))) {
223 223 case DATA_TYPE_BOOLEAN:
224 224 return (v8::Undefined());
225 225 case DATA_TYPE_BOOLEAN_VALUE:
226 226 RETURN_JS(pp, Boolean, boolean_t, bool, boolean_value);
227 227 case DATA_TYPE_BYTE:
228 228 {
229 229 uint8_t _v = (uint8_t)-1;
230 230
231 231 if (nvpair_value_byte(const_cast<nvpair_t *>(pp), &_v) != 0 ||
232 232 _v != 0) {
233 233 v8plus_panic("bad byte value %02x\n", _v);
234 234 }
235 235
236 236 return (v8::Null());
237 237 }
238 238 case DATA_TYPE_INT8:
239 239 RETURN_JS(pp, Number, int8_t, double, int8);
240 240 case DATA_TYPE_UINT8:
241 241 RETURN_JS(pp, Number, uint8_t, double, uint8);
242 242 case DATA_TYPE_INT16:
243 243 RETURN_JS(pp, Number, int16_t, double, int16);
244 244 case DATA_TYPE_UINT16:
245 245 RETURN_JS(pp, Number, uint16_t, double, uint16);
246 246 case DATA_TYPE_INT32:
247 247 RETURN_JS(pp, Number, int32_t, double, int32);
248 248 case DATA_TYPE_UINT32:
249 249 RETURN_JS(pp, Number, uint32_t, double, uint32);
250 250 case DATA_TYPE_INT64:
251 251 RETURN_JS(pp, Number, int64_t, double, int64);
252 252 case DATA_TYPE_UINT64:
253 253 RETURN_JS(pp, Number, uint64_t, double, uint64);
254 254 case DATA_TYPE_DOUBLE:
255 255 RETURN_JS(pp, Number, double, double, double);
256 256 case DATA_TYPE_STRING:
257 257 RETURN_JS(pp, String, char *, const char *, string);
258 258 case DATA_TYPE_UINT64_ARRAY:
259 259 {
260 260 std::unordered_map<uint64_t, cb_hdl_t>::iterator it;
261 261 uint64_t *vp;
262 262 uint_t nv;
263 263 int err;
264 264
265 265 if ((err = nvpair_value_uint64_array(const_cast<nvpair_t *>(pp),
266 266 &vp, &nv)) != 0)
267 267 v8plus_panic("bad JSFUNC pair: %s", strerror(err));
268 268 if (nv != 1)
269 269 v8plus_panic("bad uint64 array length %u", nv);
270 270 if ((it = cbhash.find(*vp)) == cbhash.end())
271 271 v8plus_panic("callback hash tag %llu not found", *vp);
272 272
273 273 return (it->second.ch_hdl);
274 274 }
275 275 case DATA_TYPE_NVLIST:
276 276 {
277 277 nvlist_t *lp;
278 278 v8::Local<v8::Object> oh;
279 279
280 280 (void) nvpair_value_nvlist(const_cast<nvpair_t *>(pp), &lp);
281 281
282 282 if (nvlist_lookup_string(const_cast<nvlist_t *>(lp),
283 283 V8PLUS_OBJ_TYPE_MEMBER, const_cast<char **>(&type)) != 0)
284 284 type = "Object";
285 285
286 286 if (strcmp(type, "Array") == 0)
287 287 oh = v8::Array::New()->ToObject();
288 288 else if (strcmp(type, "Object") != 0)
289 289 v8plus_panic("bad object type %s\n", type);
290 290 else
291 291 oh = v8::Object::New();
292 292
293 293 decorate_object(oh, lp);
294 294 return (oh);
295 295 }
296 296 default:
297 297 v8plus_panic("bad data type %d\n",
298 298 nvpair_type(const_cast<nvpair_t *>(pp)));
299 299 }
300 300
301 301 /*NOTREACHED*/
302 302 return (v8::Undefined());
303 303 }
304 304
305 305 #undef RETURN_JS
306 306
307 307 static uint_t
308 308 nvlist_length(const nvlist_t *lp)
309 309 {
310 310 uint_t l = 0;
311 311 nvpair_t *pp = NULL;
312 312
313 313 while ((pp =
314 314 nvlist_next_nvpair(const_cast<nvlist_t *>(lp), pp)) != NULL)
315 315 ++l;
316 316
317 317 return (l);
318 318 }
319 319
320 320 static void
321 321 nvlist_to_v8_argv(const nvlist_t *lp, int *argcp, v8::Handle<v8::Value> *argv)
322 322 {
323 323 nvpair_t *pp;
324 324 char name[16];
325 325 int i;
326 326
327 327 for (i = 0; i < *argcp; i++) {
328 328 (void) snprintf(name, sizeof (name), "%u", i);
329 329 if (nvlist_lookup_nvpair(const_cast<nvlist_t *>(lp),
330 330 name, &pp) != 0)
331 331 break;
332 332 argv[i] = v8plus::nvpair_to_v8_Value(pp);
333 333 }
334 334
335 335 *argcp = i;
336 336 }
337 337
338 338 static v8::Local<v8::Value>
339 339 sexception(const char *type, const nvlist_t *lp, const char *msg)
340 340 {
341 341 char *ctor_name;
342 342 v8::Local<v8::Value> (*excp_ctor)(v8::Handle<v8::String>);
343 343 void *obj_hdl;
344 344 size_t len;
345 345 v8::Local<v8::Value> excp;
346 346 v8::Local<v8::Object> obj;
347 347 v8::Local<v8::String> jsmsg = v8::String::New(msg);
348 348
349 349 if (type == NULL) {
350 350 type = v8plus_excptype(_v8plus_errno);
351 351 if (type == NULL)
352 352 type = "Error";
353 353 }
354 354
355 355 len = snprintf(NULL, 0, V8_EXCEPTION_CTOR_FMT,
356 356 (uint_t)strlen(type), type);
357 357 ctor_name = reinterpret_cast<char *>(alloca(len + 1));
358 358 (void) snprintf(ctor_name, len + 1, V8_EXCEPTION_CTOR_FMT,
359 359 (uint_t)strlen(type), type);
360 360
361 361 obj_hdl = dlopen(NULL, RTLD_NOLOAD);
362 362 if (obj_hdl == NULL)
363 363 v8plus_panic("%s\n", dlerror());
364 364
365 365 excp_ctor = (v8::Local<v8::Value>(*)(v8::Handle<v8::String>))(
366 366 dlsym(obj_hdl, ctor_name));
367 367
368 368 if (excp_ctor == NULL) {
369 369 (void) dlclose(obj_hdl);
370 370 if (strcmp(type, "Error") == 0) {
371 371 v8plus_panic("Unable to find %s, aborting\n",
372 372 ctor_name);
373 373 } else {
374 374 excp = v8::Exception::Error(v8::String::New(
375 375 "Nested exception: illegal exception type"));
376 376 return (excp);
377 377 }
378 378 }
379 379
380 380 excp = excp_ctor(jsmsg);
381 381 (void) dlclose(obj_hdl);
382 382
383 383 if (lp == NULL)
384 384 return (excp);
385 385
386 386 obj = excp->ToObject();
387 387 decorate_object(obj, lp);
388 388
389 389 return (excp);
390 390 }
391 391
392 392 v8::Local<v8::Value>
393 393 v8plus::exception(const char *type, const nvlist_t *lp, const char *fmt, ...)
394 394 {
395 395 v8::Local<v8::Value> exception;
396 396 char *msg;
397 397 size_t len;
398 398 va_list ap;
399 399
400 400 if (fmt != NULL) {
401 401 va_start(ap, fmt);
402 402 len = vsnprintf(NULL, 0, fmt, ap);
403 403 va_end(ap);
404 404 msg = reinterpret_cast<char *>(alloca(len + 1));
405 405
406 406 va_start(ap, fmt);
407 407 (void) vsnprintf(msg, len + 1, fmt, ap);
408 408 va_end(ap);
409 409 } else {
410 410 msg = _v8plus_errmsg;
411 411 }
412 412
413 413 exception = sexception(type, lp, msg);
414 414
415 415 return (exception);
416 416 }
417 417
418 418 extern "C" nvlist_t *
419 419 v8plus_call_direct(v8plus_jsfunc_t f, const nvlist_t *lp)
420 420 {
421 421 std::unordered_map<uint64_t, cb_hdl_t>::iterator it;
422 422 const int max_argc = nvlist_length(lp);
423 423 int argc, err;
424 424 v8::Handle<v8::Value> argv[max_argc];
425 425 v8::Handle<v8::Value> res;
426 426 nvlist_t *rp;
427 427
428 428 if ((it = cbhash.find(f)) == cbhash.end())
429 429 v8plus_panic("callback hash tag %llu not found", f);
430 430
431 431 argc = max_argc;
432 432 nvlist_to_v8_argv(lp, &argc, argv);
433 433
434 434 if ((err = nvlist_alloc(&rp, NV_UNIQUE_NAME, 0)) != 0)
435 435 return (v8plus_nverr(err, NULL));
436 436
437 437 v8::TryCatch tc;
438 438 res = it->second.ch_hdl->Call(v8::Context::GetCurrent()->Global(),
439 439 argc, argv);
440 440 if (tc.HasCaught()) {
441 441 err = nvlist_add_v8_Value(rp, "err", tc.Exception());
442 442 tc.Reset();
443 443 if (err != 0) {
444 444 nvlist_free(rp);
445 445 return (v8plus_nverr(err, "err"));
446 446 }
447 447 } else if ((err = nvlist_add_v8_Value(rp, "res", res)) != 0) {
448 448 nvlist_free(rp);
449 449 return (v8plus_nverr(err, "res"));
450 450 }
451 451
452 452 return (rp);
453 453 }
454 454
455 455 extern "C" nvlist_t *
456 456 v8plus_method_call_direct(void *cop, const char *name, const nvlist_t *lp)
457 457 {
458 458 v8plus::ObjectWrap *op = v8plus::ObjectWrap::objlookup(cop);
459 459 const int max_argc = nvlist_length(lp);
460 460 int argc, err;
461 461 v8::Handle<v8::Value> argv[max_argc];
462 462 v8::Handle<v8::Value> res;
463 463 nvlist_t *rp;
464 464
465 465 if (v8plus_in_event_thread() != _B_TRUE)
466 466 v8plus_panic("direct method call outside of event loop");
467 467
468 468 argc = max_argc;
469 469 nvlist_to_v8_argv(lp, &argc, argv);
470 470
471 471 if ((err = nvlist_alloc(&rp, NV_UNIQUE_NAME, 0)) != 0)
472 472 return (v8plus_nverr(err, NULL));
473 473
474 474 v8::TryCatch tc;
475 475 res = op->call(name, argc, argv);
476 476 if (tc.HasCaught()) {
477 477 err = nvlist_add_v8_Value(rp, "err", tc.Exception());
478 478 tc.Reset();
479 479 if (err != 0) {
480 480 nvlist_free(rp);
481 481 return (v8plus_nverr(err, "err"));
482 482 }
483 483 } else if ((err = nvlist_add_v8_Value(rp, "res", res)) != 0) {
484 484 nvlist_free(rp);
485 485 return (v8plus_nverr(err, "res"));
486 486 }
487 487
488 488 return (rp);
489 489 }
490 490
491 491 extern "C" int
492 492 nvlist_lookup_v8plus_jsfunc(const nvlist_t *lp, const char *name,
493 493 v8plus_jsfunc_t *vp)
494 494 {
495 495 uint64_t *lvp;
496 496 uint_t nv;
497 497 int err;
498 498
499 499 err = nvlist_lookup_uint64_array(const_cast<nvlist_t *>(lp),
500 500 name, &lvp, &nv);
501 501 if (err != 0)
502 502 return (err);
503 503
504 504 if (nv != 1)
505 505 v8plus_panic("bad array size %u for callback hash tag", nv);
506 506
507 507 *vp = *lvp;
508 508 return (0);
509 509 }
510 510
511 511 extern "C" void
512 512 v8plus_jsfunc_hold(v8plus_jsfunc_t f)
513 513 {
514 514 v8::Persistent<v8::Function> pfh;
515 515 std::unordered_map<uint64_t, cb_hdl_t>::iterator it;
↓ open down ↓ |
515 lines elided |
↑ open up ↑ |
516 516
517 517 if ((it = cbhash.find(f)) == cbhash.end())
518 518 v8plus_panic("callback hash tag %llu not found", f);
519 519
520 520 if (!it->second.ch_persist) {
521 521 pfh = v8::Persistent<v8::Function>::New(it->second.ch_hdl);
522 522 it->second.ch_hdl = pfh;
523 523 it->second.ch_persist = _B_TRUE;
524 524 }
525 525 ++it->second.ch_refs;
526 +
527 + /*
528 + * If the consumer puts a hold on a callback, we should also put a hold
529 + * on the V8 event loop to prevent it dematerialising beneath us.
530 + */
531 + v8plus_eventloop_hold();
526 532 }
527 533
528 534 extern "C" void
529 535 v8plus_jsfunc_rele_direct(v8plus_jsfunc_t f)
530 536 {
531 537 v8::Local<v8::Function> lfh;
532 538 std::unordered_map<uint64_t, cb_hdl_t>::iterator it;
533 539
534 540 if ((it = cbhash.find(f)) == cbhash.end())
535 541 v8plus_panic("callback hash tag %llu not found", f);
536 542
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
537 543 if (it->second.ch_refs == 0)
538 544 v8plus_panic("releasing unheld callback hash tag %llu", f);
539 545
540 546 if (--it->second.ch_refs == 0) {
541 547 if (it->second.ch_persist) {
542 548 v8::Persistent<v8::Function> pfh(it->second.ch_hdl);
543 549 pfh.Dispose();
544 550 }
545 551 cbhash.erase(it);
546 552 }
553 +
554 + /*
555 + * Release the event loop hold we took in v8plus_jsfunc_hold():
556 + */
557 + v8plus_eventloop_rele_direct();
547 558 }
548 559
549 560 static size_t
550 561 library_name(const char *base, const char *version, char *buf, size_t len)
551 562 {
552 563 #ifdef __MACH__
553 564 return (snprintf(buf, len, "lib%s.%s%sdylib", base,
554 565 version ? version : "", version ? "." : ""));
555 566 #else
556 567 return (snprintf(buf, len, "lib%s.so%s%s", base,
557 568 version ? "." : "", version ? version : ""));
558 569 #endif
559 570 }
560 571
561 572 /*
562 573 * This is really gross: we need to free up JS function slots when then list
563 574 * is freed, but there's no way for us to know that's happening. So we
564 575 * interpose on nvlist_free() here, checking for function slots to free iff
565 576 * this is a list that has a V8 JS function handle in it. Lists created by
566 577 * someone else, even if they have uint64 arrays in them, are passed through.
567 578 * This whole thing makes me want to cry. Why can't we just have a decent
568 579 * JS VM?!
569 580 */
570 581 extern "C" void
571 582 nvlist_free(nvlist_t *lp)
572 583 {
573 584 uint64_t *vp;
574 585 uint_t nv;
575 586 nvpair_t *pp = NULL;
576 587
577 588 if (lp == NULL)
578 589 return;
579 590
580 591 if (__real_nvlist_free == NULL) {
581 592 char *libname;
582 593 size_t len;
583 594 void *dlhdl;
584 595
585 596 len = library_name("nvpair", "1", NULL, 0) + 1;
586 597 libname = reinterpret_cast<char *>(alloca(len));
587 598 (void) library_name("nvpair", "1", libname, len);
588 599
589 600 dlhdl = dlopen(libname, RTLD_LAZY | RTLD_LOCAL);
590 601 if (dlhdl == NULL) {
591 602 v8plus_panic("unable to dlopen libnvpair: %s",
592 603 dlerror());
593 604 }
594 605 __real_nvlist_free = (void (*)(nvlist_t *))
595 606 dlsym(dlhdl, "nvlist_free");
596 607 if (__real_nvlist_free == NULL)
597 608 v8plus_panic("unable to find nvlist_free");
598 609 }
599 610
600 611 if (nvlist_exists(lp, V8PLUS_JSF_COOKIE)) {
601 612 while ((pp = nvlist_next_nvpair(lp, pp)) != NULL) {
602 613 if (nvpair_type(pp) != DATA_TYPE_UINT64_ARRAY)
603 614 continue;
604 615 if (nvpair_value_uint64_array(pp, &vp, &nv) != 0) {
605 616 v8plus_panic(
606 617 "unable to obtain callbach hash tag");
607 618 }
608 619 if (nv != 1) {
609 620 v8plus_panic(
610 621 "bad array size %u for callback hash tag",
611 622 nv);
612 623 }
613 624 v8plus_jsfunc_rele(*vp);
614 625 }
615 626 }
616 627
617 628 __real_nvlist_free(lp);
618 629 }
619 630
620 631 extern "C" int
621 632 nvpair_value_v8plus_jsfunc(const nvpair_t *pp, v8plus_jsfunc_t *vp)
622 633 {
623 634 uint64_t *lvp;
624 635 uint_t nv;
625 636 int err;
626 637
627 638 if ((err = nvpair_value_uint64_array((nvpair_t *)pp, &lvp, &nv)) != 0)
628 639 return (err);
629 640
↓ open down ↓ |
73 lines elided |
↑ open up ↑ |
630 641 *vp = *lvp;
631 642
632 643 return (0);
633 644 }
634 645
635 646 extern "C" void
636 647 v8plus_obj_hold(const void *cop)
637 648 {
638 649 v8plus::ObjectWrap *op = v8plus::ObjectWrap::objlookup(cop);
639 650 op->public_Ref();
651 +
652 + /*
653 + * If the consumer puts a hold on an object, we should also put a hold
654 + * on the V8 event loop to prevent it dematerialising beneath us.
655 + */
656 + v8plus_eventloop_hold();
640 657 }
641 658
642 659 extern "C" void
643 660 v8plus_obj_rele_direct(const void *cop)
644 661 {
645 662 v8plus::ObjectWrap *op = v8plus::ObjectWrap::objlookup(cop);
646 663 op->public_Unref();
664 +
665 + /*
666 + * Release the event loop hold we took in v8plus_obj_hold():
667 + */
668 + v8plus_eventloop_rele_direct();
647 669 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX