Print this page
XXX rework to avoid changing api
XXX well, it works now...
Split |
Close |
Expand all |
Collapse all |
--- old/./v8plus_objectwrap.cc
+++ new/./v8plus_objectwrap.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 <string.h>
7 7 #include <new>
8 8 #include <unordered_map>
9 9 #include <stdlib.h>
10 10 #include <node.h>
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
11 11 #include "v8plus_impl.h"
12 12 #include "v8plus_glue.h"
13 13
14 14 #define METHOD_NAME_FMT "__v8plus_%s_%s"
15 15
16 16 v8::Persistent<v8::Function> v8plus::ObjectWrap::_constructor;
17 17 v8plus_method_descr_t *v8plus::ObjectWrap::_mtbl;
18 18 v8plus_static_descr_t *v8plus::ObjectWrap::_stbl;
19 19 std::unordered_map<void *, v8plus::ObjectWrap *> v8plus::ObjectWrap::_objhash;
20 20
21 +uv_async_t v8plus::ObjectWrap::_uv_async;
22 +pthread_mutex_t v8plus::ObjectWrap::_callq_mutex;
23 +std::queue<v8plus_async_call_t *> v8plus::ObjectWrap::_callq;
24 +boolean_t v8plus::ObjectWrap::_crossthread_init_done = _B_FALSE;
25 +unsigned long v8plus::ObjectWrap::_uv_event_thread;
26 +
21 27 static char *
22 28 function_name(const char *lambda)
23 29 {
24 30 char *fn;
25 31 size_t len;
26 32
27 33 len = snprintf(NULL, 0, METHOD_NAME_FMT,
28 34 v8plus_js_class_name, lambda);
29 35 if ((fn = (char *)malloc(len + 1)) == NULL)
30 36 v8plus_panic("out of memory for function name for %s", lambda);
31 37
32 38 (void) snprintf(fn, len + 1, METHOD_NAME_FMT,
33 39 v8plus_js_class_name, lambda);
34 40
35 41 return (fn);
36 42 }
37 43
38 44 void
39 45 v8plus::ObjectWrap::init(v8::Handle<v8::Object> target)
40 46 {
41 47 uint_t i;
42 48
43 49 if (v8plus_static_method_count > 0) {
44 50 const v8plus_static_descr_t *sdp;
45 51
46 52 _stbl = new (std::nothrow)
47 53 v8plus_static_descr_t[v8plus_static_method_count];
48 54 if (_stbl == NULL)
49 55 v8plus_panic("out of memory for static method table");
50 56
51 57 for (i = 0; i < v8plus_static_method_count; i++) {
52 58 v8::Local<v8::FunctionTemplate> fth =
53 59 v8::FunctionTemplate::New(_static_entry);
54 60 v8::Local<v8::Function> fh = fth->GetFunction();
55 61 sdp = &v8plus_static_methods[i];
56 62
57 63 _stbl[i].sd_name = function_name(sdp->sd_name);
58 64 _stbl[i].sd_c_func = sdp->sd_c_func;
59 65
60 66 fh->SetName(v8::String::New(_stbl[i].sd_name));
61 67
62 68 target->Set(v8::String::NewSymbol(sdp->sd_name), fh);
63 69 }
64 70 }
65 71
66 72
67 73 if (v8plus_method_count > 0) {
68 74 v8::Local<v8::FunctionTemplate> tpl =
69 75 v8::FunctionTemplate::New(_new);
70 76 const v8plus_method_descr_t *mdp;
71 77
72 78 _mtbl = new (std::nothrow)
73 79 v8plus_method_descr_t[v8plus_method_count];
74 80 if (_mtbl == NULL)
75 81 v8plus_panic("out of memory for method table");
76 82
77 83 tpl->SetClassName(v8::String::NewSymbol(v8plus_js_class_name));
78 84 tpl->InstanceTemplate()->SetInternalFieldCount(
79 85 v8plus_method_count);
80 86
81 87 for (i = 0; i < v8plus_method_count; i++) {
82 88 v8::Local<v8::FunctionTemplate> fth =
83 89 v8::FunctionTemplate::New(_entry);
84 90 v8::Local<v8::Function> fh = fth->GetFunction();
85 91 mdp = &v8plus_methods[i];
86 92
87 93 _mtbl[i].md_name = function_name(mdp->md_name);
88 94 _mtbl[i].md_c_func = mdp->md_c_func;
89 95
90 96 fh->SetName(v8::String::New(_mtbl[i].md_name));
91 97
92 98 tpl->PrototypeTemplate()->Set(
93 99 v8::String::NewSymbol(mdp->md_name), fh);
94 100 }
95 101
96 102 _constructor =
97 103 v8::Persistent<v8::Function>::New(tpl->GetFunction());
98 104
99 105 target->Set(v8::String::NewSymbol(v8plus_js_factory_name),
100 106 v8::FunctionTemplate::New(
101 107 v8plus::ObjectWrap::cons)->GetFunction());
102 108 }
103 109 }
104 110
105 111 v8::Handle<v8::Value>
↓ open down ↓ |
75 lines elided |
↑ open up ↑ |
106 112 v8plus::ObjectWrap::_new(const v8::Arguments &args)
107 113 {
108 114 v8::HandleScope scope;
109 115 v8plus::ObjectWrap *op = new v8plus::ObjectWrap();
110 116 nvlist_t *c_excp;
111 117 nvlist_t *c_args;
112 118
113 119 if ((c_args = v8plus::v8_Arguments_to_nvlist(args)) == NULL)
114 120 return (V8PLUS_THROW_DEFAULT());
115 121
122 + if (_crossthread_init_done == _B_FALSE) {
123 + /*
124 + * Initialise structures for off-event-loop method calls.
125 + *
126 + * Note that uv_async_init() must be called inside the libuv
127 + * Event Loop, so we do it here. We also want to record the
128 + * thread ID of the Event Loop thread so as to determine what
129 + * kind of method calls to make later.
130 + */
131 + _uv_event_thread = pthread_self();
132 + if (uv_async_init(uv_default_loop(), &_uv_async,
133 + v8plus_async_callback) != 0)
134 + v8plus_panic("unable to initialise uv_async_t");
135 + if (pthread_mutex_init(&_callq_mutex, NULL) != 0)
136 + v8plus_panic("unable to initialise mutex");
137 + _crossthread_init_done = _B_TRUE;
138 + }
139 +
116 140 c_excp = v8plus_ctor(c_args, &op->_c_impl);
117 141 nvlist_free(c_args);
118 142 if (op->_c_impl == NULL) {
119 143 if (c_excp == NULL) {
120 144 return (V8PLUS_THROW_DEFAULT());
121 145 } else {
122 146 return (V8PLUS_THROW_DECORATED(c_excp));
123 147 }
124 148 }
125 149
126 150 _objhash.insert(std::make_pair(op->_c_impl, op));
127 151 op->Wrap(args.This());
128 152
129 153 return (args.This());
130 154 }
131 155
132 156 v8plus::ObjectWrap::~ObjectWrap()
133 157 {
134 158 v8plus_dtor(_c_impl);
135 159 (void) _objhash.erase(_c_impl);
136 160 }
137 161
138 162 v8::Handle<v8::Value>
139 163 v8plus::ObjectWrap::cons(const v8::Arguments &args)
140 164 {
141 165 v8::HandleScope scope;
142 166 const unsigned argc = 1;
143 167 v8::Handle<v8::Value> argv[argc] = { args[0] };
144 168 v8::Local<v8::Object> instance = _constructor->NewInstance(argc, argv);
145 169
146 170 return (scope.Close(instance));
147 171 }
148 172
149 173 v8plus::ObjectWrap *
150 174 v8plus::ObjectWrap::objlookup(const void *cop)
151 175 {
152 176 std::unordered_map<void *, v8plus::ObjectWrap *>::iterator it;
153 177
154 178 if ((it = _objhash.find(const_cast<void *>(cop))) == _objhash.end())
155 179 v8plus_panic("unable to find C++ wrapper for %p\n", cop);
156 180
157 181 return (it->second);
158 182 }
159 183
160 184 /*
161 185 * This is the entry point for all methods. We will start by demultiplexing
162 186 * out the C method from the function name by which we were called. There is
163 187 * probably some mechanism by which overly clever JavaScript code could make
164 188 * this not match the actual name; this will kill your Node process, so don't
165 189 * get cute.
166 190 */
167 191 v8::Handle<v8::Value>
168 192 v8plus::ObjectWrap::_entry(const v8::Arguments &args)
169 193 {
170 194 v8::HandleScope scope;
171 195 v8plus::ObjectWrap *op =
172 196 node::ObjectWrap::Unwrap<v8plus::ObjectWrap>(args.This());
173 197 nvlist_t *c_args;
174 198 nvlist_t *c_out;
175 199 nvlist_t *excp;
176 200 nvpair_t *rpp;
177 201 v8::Local<v8::String> self = args.Callee()->GetName()->ToString();
178 202 v8::String::Utf8Value selfsv(self);
179 203 const char *fn = *selfsv;
180 204 const v8plus_method_descr_t *mdp;
181 205 v8plus_c_method_f c_method = NULL;
182 206 uint_t i;
183 207
184 208 for (i = 0; i < v8plus_method_count; i++) {
185 209 mdp = &_mtbl[i];
186 210 if (strcmp(mdp->md_name, fn) == 0) {
187 211 c_method = mdp->md_c_func;
188 212 break;
189 213 }
190 214 }
191 215
192 216 if (c_method == NULL)
193 217 v8plus_panic("impossible method name %s\n", fn);
194 218
195 219 if ((c_args = v8plus::v8_Arguments_to_nvlist(args)) == NULL)
196 220 return (V8PLUS_THROW_DEFAULT());
197 221
198 222 c_out = c_method(op->_c_impl, c_args);
199 223 nvlist_free(c_args);
200 224
201 225 if (c_out == NULL) {
202 226 if (_v8plus_errno == V8PLUSERR_NOERROR)
203 227 return (scope.Close(v8::Undefined()));
204 228 else
205 229 return (V8PLUS_THROW_DEFAULT());
206 230 } else {
207 231 if (nvlist_lookup_nvlist(c_out, "err", &excp) == 0) {
208 232 v8::Handle<v8::Value> x = V8PLUS_THROW_DECORATED(excp);
209 233 nvlist_free(c_out);
210 234 return (x);
211 235 } else if (nvlist_lookup_nvpair(c_out, "res", &rpp) == 0) {
212 236 v8::Handle<v8::Value> r =
213 237 v8plus::nvpair_to_v8_Value(rpp);
214 238 nvlist_free(c_out);
215 239 return (scope.Close(r));
216 240 } else {
217 241 v8plus_panic("bad encoded object in return");
218 242 }
219 243 }
220 244
221 245 /*NOTREACHED*/
222 246 return (v8::Undefined());
223 247 }
224 248
225 249 v8::Handle<v8::Value>
226 250 v8plus::ObjectWrap::_static_entry(const v8::Arguments &args)
227 251 {
228 252 v8::HandleScope scope;
229 253 nvlist_t *c_args;
230 254 nvlist_t *c_out;
231 255 nvlist_t *excp;
232 256 nvpair_t *rpp;
233 257 v8::Local<v8::String> self = args.Callee()->GetName()->ToString();
234 258 v8::String::Utf8Value selfsv(self);
235 259 const char *fn = *selfsv;
236 260 const v8plus_static_descr_t *sdp;
237 261 v8plus_c_static_f c_static = NULL;
238 262 uint_t i;
239 263
240 264 for (i = 0; i < v8plus_static_method_count; i++) {
241 265 sdp = &_stbl[i];
242 266 if (strcmp(sdp->sd_name, fn) == 0) {
243 267 c_static = sdp->sd_c_func;
244 268 break;
245 269 }
246 270 }
247 271
248 272 if (c_static == NULL)
249 273 v8plus_panic("impossible static method name %s\n", fn);
250 274
251 275 if ((c_args = v8plus::v8_Arguments_to_nvlist(args)) == NULL)
252 276 return (V8PLUS_THROW_DEFAULT());
253 277
254 278 c_out = c_static(c_args);
255 279 nvlist_free(c_args);
256 280
257 281 if (c_out == NULL) {
258 282 if (_v8plus_errno == V8PLUSERR_NOERROR)
259 283 return (scope.Close(v8::Undefined()));
260 284 else
261 285 return (V8PLUS_THROW_DEFAULT());
262 286 } else {
263 287 if (nvlist_lookup_nvlist(c_out, "err", &excp) == 0) {
264 288 v8::Handle<v8::Value> x = V8PLUS_THROW_DECORATED(excp);
265 289 nvlist_free(c_out);
266 290 return (x);
267 291 } else if (nvlist_lookup_nvpair(c_out, "res", &rpp) == 0) {
268 292 v8::Handle<v8::Value> r =
269 293 v8plus::nvpair_to_v8_Value(rpp);
270 294 nvlist_free(c_out);
271 295 return (scope.Close(r));
272 296 } else {
273 297 v8plus_panic("bad encoded object in return");
274 298 }
275 299 }
276 300
277 301 /*NOTREACHED*/
278 302 return (v8::Undefined());
279 303 }
280 304
281 305 v8::Handle<v8::Value>
282 306 v8plus::ObjectWrap::call(const char *name,
283 307 int argc, v8::Handle<v8::Value> argv[])
284 308 {
285 309 v8::Handle<v8::Value> v = v8::Undefined();
286 310 v8::Local<v8::Value> f = handle_->Get(v8::String::NewSymbol(name));
287 311
288 312 /*
289 313 * XXX - we'd like to throw here, but for some reason our TryCatch
290 314 * block doesn't seem to handle the exception.
291 315 */
292 316 if (!f->IsFunction())
293 317 return (v8::Undefined());
294 318
295 319 #ifdef NODE_MAKECALLBACK_RETURN
296 320 v =
297 321 #endif
298 322 node::MakeCallback(handle_, name, argc, argv);
299 323
300 324 return (v);
301 325 }
302 326
303 327 void
304 328 v8plus::ObjectWrap::public_Ref(void)
↓ open down ↓ |
179 lines elided |
↑ open up ↑ |
305 329 {
306 330 this->Ref();
307 331 }
308 332
309 333 void
310 334 v8plus::ObjectWrap::public_Unref(void)
311 335 {
312 336 this->Unref();
313 337 }
314 338
339 +boolean_t
340 +v8plus::ObjectWrap::in_event_thread(void)
341 +{
342 + if (_crossthread_init_done != _B_TRUE)
343 + v8plus_panic("cross thread call init not done!");
344 +
345 + return (_uv_event_thread == pthread_self() ? _B_TRUE : _B_FALSE);
346 +}
347 +
348 +v8plus_async_call_t *
349 +v8plus::ObjectWrap::next_async_call(void)
350 +{
351 + v8plus_async_call_t *ret = NULL;
352 +
353 + if (pthread_mutex_lock(&_callq_mutex) != 0)
354 + v8plus_panic("could not lock callq mutex");
355 +
356 + if (!_callq.empty()) {
357 + ret = _callq.front();
358 + _callq.pop();
359 + }
360 +
361 + if (pthread_mutex_unlock(&_callq_mutex) != 0)
362 + v8plus_panic("could not release callq mutex");
363 +
364 + return (ret);
365 +}
366 +
367 +void
368 +v8plus::ObjectWrap::post_async_call(v8plus_async_call_t *ac)
369 +{
370 + if (pthread_mutex_lock(&_callq_mutex) != 0)
371 + v8plus_panic("could not lock callq mutex");
372 +
373 + _callq.push(ac);
374 +
375 + if (pthread_mutex_unlock(&_callq_mutex) != 0)
376 + v8plus_panic("could not release callq mutex");
377 +
378 + uv_async_send(&_uv_async);
379 +}
380 +
315 381 extern "C" void
316 382 init(v8::Handle<v8::Object> target)
317 383 {
318 384 v8plus::ObjectWrap::init(target);
319 385 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX