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 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
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 */
54 void *vac_cop;
55 const char *vac_name;
56 /*
57 * For ACT_JSFUNC_{CALL,RELEASE}:
58 */
104 * Run the queued method:
105 */
106 if (vac->vac_flags & ACF_COMPLETED)
107 v8plus_panic("async call already run");
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 }
137
138 if (pthread_mutex_lock(&vac->vac_mtx) != 0)
139 v8plus_panic("could not lock async call mutex");
140 vac->vac_flags |= ACF_COMPLETED;
141 if (pthread_cond_broadcast(&vac->vac_cv) != 0)
142 v8plus_panic("could not signal async call condvar");
143 if (pthread_mutex_unlock(&vac->vac_mtx) != 0)
287
288 (void) v8plus_cross_thread_call(vac);
289 }
290
291 /*
292 * Initialise structures for off-event-loop method calls.
293 *
294 * Note that uv_async_init() must be called inside the libuv event loop, so we
295 * do it here. We also want to record the thread ID of the Event Loop thread
296 * so as to determine what kind of method calls to make later.
297 */
298 void
299 v8plus_crossthread_init(void)
300 {
301 _v8plus_uv_event_thread = pthread_self();
302 if (uv_async_init(uv_default_loop(), &_v8plus_uv_async,
303 v8plus_async_callback) != 0)
304 v8plus_panic("unable to initialise uv_async_t");
305 if (pthread_mutex_init(&_v8plus_callq_mtx, NULL) != 0)
306 v8plus_panic("unable to initialise mutex");
307 }
308
309 nvlist_t *
310 v8plus_verror(v8plus_errno_t e, const char *fmt, va_list ap)
311 {
312 if (fmt == NULL) {
313 if (e == V8PLUSERR_NOERROR) {
314 *_v8plus_errmsg = '\0';
315 } else {
316 (void) snprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN,
317 "%s", v8plus_strerror(e));
318 }
319 } else {
320 (void) vsnprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN, fmt, ap);
321 }
322 _v8plus_errno = e;
323
324 return (NULL);
325 }
326
|
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 static int _v8plus_eventloop_refcount;
35
36 typedef enum v8plus_async_call_type {
37 ACT_OBJECT_CALL = 1,
38 ACT_OBJECT_RELEASE,
39 ACT_JSFUNC_CALL,
40 ACT_JSFUNC_RELEASE,
41 ACT_EVENTLOOP_RELEASE
42 } v8plus_async_call_type_t;
43
44 typedef enum v8plus_async_call_flags {
45 ACF_COMPLETED = 0x01,
46 ACF_NOREPLY = 0x02
47 } v8plus_async_call_flags_t;
48
49
50 typedef struct v8plus_async_call {
51 v8plus_async_call_type_t vac_type;
52 v8plus_async_call_flags_t vac_flags;
53
54 /*
55 * For ACT_OBJECT_{CALL,RELEASE}:
56 */
57 void *vac_cop;
58 const char *vac_name;
59 /*
60 * For ACT_JSFUNC_{CALL,RELEASE}:
61 */
107 * Run the queued method:
108 */
109 if (vac->vac_flags & ACF_COMPLETED)
110 v8plus_panic("async call already run");
111
112 switch (vac->vac_type) {
113 case ACT_OBJECT_CALL:
114 vac->vac_return = v8plus_method_call_direct(
115 vac->vac_cop, vac->vac_name, vac->vac_lp);
116 break;
117 case ACT_OBJECT_RELEASE:
118 v8plus_obj_rele_direct(vac->vac_cop);
119 break;
120 case ACT_JSFUNC_CALL:
121 vac->vac_return = v8plus_call_direct(
122 vac->vac_func, vac->vac_lp);
123 break;
124 case ACT_JSFUNC_RELEASE:
125 v8plus_jsfunc_rele_direct(vac->vac_func);
126 break;
127 case ACT_EVENTLOOP_RELEASE:
128 v8plus_eventloop_rele_direct();
129 break;
130 }
131
132 if (vac->vac_flags & ACF_NOREPLY) {
133 /*
134 * The caller posted this event and is not sleeping
135 * on a reply. Just free the call structure and move
136 * on.
137 */
138 free(vac);
139 if (vac->vac_lp != NULL)
140 nvlist_free((nvlist_t *)vac->vac_lp);
141 continue;
142 }
143
144 if (pthread_mutex_lock(&vac->vac_mtx) != 0)
145 v8plus_panic("could not lock async call mutex");
146 vac->vac_flags |= ACF_COMPLETED;
147 if (pthread_cond_broadcast(&vac->vac_cv) != 0)
148 v8plus_panic("could not signal async call condvar");
149 if (pthread_mutex_unlock(&vac->vac_mtx) != 0)
293
294 (void) v8plus_cross_thread_call(vac);
295 }
296
297 /*
298 * Initialise structures for off-event-loop method calls.
299 *
300 * Note that uv_async_init() must be called inside the libuv event loop, so we
301 * do it here. We also want to record the thread ID of the Event Loop thread
302 * so as to determine what kind of method calls to make later.
303 */
304 void
305 v8plus_crossthread_init(void)
306 {
307 _v8plus_uv_event_thread = pthread_self();
308 if (uv_async_init(uv_default_loop(), &_v8plus_uv_async,
309 v8plus_async_callback) != 0)
310 v8plus_panic("unable to initialise uv_async_t");
311 if (pthread_mutex_init(&_v8plus_callq_mtx, NULL) != 0)
312 v8plus_panic("unable to initialise mutex");
313
314 /*
315 * If we do not unreference the async handle, then its mere
316 * existence will keep the event loop open forever. If the consumer
317 * _wants_ this behaviour, they may call v8plus_eventloop_hold()
318 * from the event loop thread.
319 */
320 uv_unref((uv_handle_t *)&_v8plus_uv_async);
321 }
322
323 void
324 v8plus_eventloop_hold(void)
325 {
326 ++_v8plus_eventloop_refcount;
327 uv_ref((uv_handle_t *)&_v8plus_uv_async);
328 }
329
330 void
331 v8plus_eventloop_rele_direct(void)
332 {
333 if (--_v8plus_eventloop_refcount < 1) {
334 _v8plus_eventloop_refcount = 0;
335 uv_unref((uv_handle_t *)&_v8plus_uv_async);
336 }
337 }
338
339 void
340 v8plus_eventloop_rele(void)
341 {
342 v8plus_async_call_t *vac;
343
344 if (v8plus_in_event_thread() == B_TRUE) {
345 return (v8plus_eventloop_rele_direct());
346 }
347
348 vac = calloc(1, sizeof (*vac));
349 if (vac == NULL)
350 v8plus_panic("could not allocate async call structure");
351
352 vac->vac_type = ACT_EVENTLOOP_RELEASE;
353 vac->vac_flags = ACF_NOREPLY;
354
355 (void) v8plus_cross_thread_call(vac);
356 }
357
358 nvlist_t *
359 v8plus_verror(v8plus_errno_t e, const char *fmt, va_list ap)
360 {
361 if (fmt == NULL) {
362 if (e == V8PLUSERR_NOERROR) {
363 *_v8plus_errmsg = '\0';
364 } else {
365 (void) snprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN,
366 "%s", v8plus_strerror(e));
367 }
368 } else {
369 (void) vsnprintf(_v8plus_errmsg, V8PLUS_ERRMSG_LEN, fmt, ap);
370 }
371 _v8plus_errno = e;
372
373 return (NULL);
374 }
375
|