1 2 /* 3 Copyright (c) 2013, Oracle and/or its affiliates. All rights 4 reserved. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License, version 2.0, 8 as published by the Free Software Foundation. 9 10 This program is also distributed with certain software (including 11 but not limited to OpenSSL) that is licensed under separate terms, 12 as designated in a particular file or component or in included license 13 documentation. The authors of MySQL hereby grant you an additional 14 permission to link the program and your derivative works with the 15 separately licensed software that they have included with MySQL. 16 17 This program is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU General Public License, version 2.0, for more details. 21 22 You should have received a copy of the GNU General Public License 23 along with this program; if not, write to the Free Software 24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 02110-1301 USA 26 */ 27 28 #ifndef NODEJS_ADAPTER_INCLUDE_ASYNCMETHODCALL_H 29 #define NODEJS_ADAPTER_INCLUDE_ASYNCMETHODCALL_H 30 #include <assert.h> 31 32 #include "JsConverter.h" 33 #include "async_common.h" 34 #include "common_v8_values.h" 35 36 using namespace v8; 37 38 39 /** These classes wrap various sorts of C and C++ functions for use as either 40 * synchronous or asynchronous JavaScript methods. 41 * 42 * There are two class hierarchies declared here. 43 * The first hierarchy is: 44 * AsyncCall 45 * -> Call_Returning<R> template over return type 46 * -> NativeMethodCall<R, C> template over class 47 * 48 * The second hierarchy is a set of alternate classes 49 * Call_1_<A0> , Call_2_<A0,A1> , .. Call_8_<A0,A1, .. A7> 50 * expressing the set of arguments to a function or method call 51 * 52 * The base class AsyncCall wraps the worker-thread run() routine and the 53 * main thread (post-run) doAsyncCallback() needed for async execution. 54 * 55 * The run() method, declared void run(void), will be scheduled to run in a 56 * uv worker thread. 57 * 58 * The doAsyncCallback() method will take a JavaScript context. It is expected 59 * to prepare the result and call the user's callback function. 60 * 61 * The templated class AsyncCall_Returning<R> inherits from AsyncCall and 62 * adds a return type, which is initialized at 0. 63 * 64 * OTHER NOTES: 65 * The standard AsyncCall constructor allocates a persistent V8 object, so 66 * it can only run in the main JavaScript thread. 67 * However, the constructor for AsyncAsyncCall runs in a UV worker thread, 68 * so there is an alternative chain of protected constructors from 69 * AsyncAsyncCall up to AsyncCall. 70 */ 71 72 73 /** Base class 74 **/ 75 class AsyncCall { 76 protected: 77 /* Member variables */ 78 Persistent<Function> callback; 79 80 /* Protected constructor chain from AsyncAsyncCall */ AsyncCall(Persistent<Function> cb)81 AsyncCall(Persistent<Function> cb) : callback(cb) {}; 82 83 public: AsyncCall(Local<Value> callbackFunc)84 AsyncCall(Local<Value> callbackFunc) { 85 callback = Persistent<Function>::New(Local<Function>::Cast(callbackFunc)); 86 } 87 88 /* Destructor */ ~AsyncCall()89 virtual ~AsyncCall() { 90 callback.Dispose(); 91 } 92 93 /* Methods (Pure virtual) */ 94 virtual void run(void) = 0; 95 virtual void doAsyncCallback(Local<Object>) = 0; 96 97 /* Base Class Virtual Methods */ handleErrors(void)98 virtual void handleErrors(void) { } 99 100 /* Base Class Fixed Methods */ runAsync()101 void runAsync() { 102 if (callback->IsCallable()) { 103 uv_work_t * req = new uv_work_t; 104 req->data = (void *) this; 105 uv_queue_work(uv_default_loop(), req, work_thd_run, main_thd_complete); 106 } 107 else { 108 ThrowException(Exception::TypeError(String::New("Uncallable Callback"))); 109 } 110 } 111 }; 112 113 114 /** First-level template class; 115 templated over return types 116 **/ 117 template <typename RETURN_TYPE> 118 class AsyncCall_Returning : public AsyncCall { 119 private: 120 /* Private Member variables */ 121 Envelope * returnValueEnvelope; 122 123 protected: 124 /* Protected Constructor Chain */ 125 AsyncCall_Returning<RETURN_TYPE>(Persistent<Function> callback) : AsyncCall(callback)126 AsyncCall(callback), returnValueEnvelope(0), error(0) {} 127 128 public: 129 /* Member variables */ 130 NativeCodeError *error; 131 RETURN_TYPE return_val; 132 133 /* Constructors */ 134 AsyncCall_Returning<RETURN_TYPE>(Local<Value> callback) : AsyncCall(callback)135 AsyncCall(callback), returnValueEnvelope(0), error(0) {} 136 137 AsyncCall_Returning<RETURN_TYPE>(Local<Value> callback, RETURN_TYPE rv) : AsyncCall(callback)138 AsyncCall(callback), returnValueEnvelope(0), error(0), return_val(rv) {} 139 140 /* Destructor */ 141 virtual ~AsyncCall_Returning<RETURN_TYPE>() { 142 if(error) delete error; 143 } 144 145 /* Methods */ wrapReturnValueAs(Envelope * env)146 void wrapReturnValueAs(Envelope *env) { 147 returnValueEnvelope = env; 148 } 149 jsReturnVal()150 Local<Value> jsReturnVal() { 151 HandleScope scope; 152 153 if(isWrappedPointer(return_val)) { 154 DEBUG_ASSERT(returnValueEnvelope); 155 Local<Object> obj = returnValueEnvelope->newWrapper(); 156 wrapPointerInObject(return_val, *returnValueEnvelope, obj); 157 return scope.Close(obj); 158 } 159 else { 160 /* Optimization for a common case */ 161 if(return_val == 0) { 162 return scope.Close(Zero()); 163 } else { 164 return scope.Close(toJS(return_val)); 165 } 166 } 167 } 168 169 /* doAsyncCallback() is an async callback, run by main_thread_complete(). 170 */ doAsyncCallback(Local<Object> context)171 void doAsyncCallback(Local<Object> context) { 172 HandleScope scope; 173 Handle<Value> cb_args[2]; 174 175 if(error) cb_args[0] = error->toJS(); 176 else cb_args[0] = Null(); 177 178 cb_args[1] = jsReturnVal(); 179 180 callback->Call(context, 2, cb_args); 181 } 182 }; 183 184 185 /** Second-level template class for C++ method calls: 186 templated over class of native object. 187 This class is the home of error handling for C++ code. 188 **/ 189 template <typename R, typename C> 190 class NativeMethodCall : public AsyncCall_Returning<R> { 191 public: 192 /* Member variables */ 193 typedef NativeCodeError * (*errorHandler_fn_t)(R, C *); 194 C * native_obj; 195 errorHandler_fn_t errorHandler; 196 197 /* Constructor */ 198 NativeMethodCall<R, C>(const Arguments &args, int callback_idx) : 199 AsyncCall_Returning<R>(args[callback_idx]), /*callback*/ 200 errorHandler(0) 201 { 202 native_obj = unwrapPointer<C *>(args.Holder()); 203 DEBUG_ASSERT(native_obj != NULL); 204 } 205 206 /* Methods */ handleErrors(void)207 void handleErrors(void) { 208 if(errorHandler) AsyncCall_Returning<R>::error = 209 errorHandler(AsyncCall_Returning<R>::return_val, native_obj); 210 } 211 212 protected: 213 /* Alternative constructor used only by AsyncAsyncCall */ 214 NativeMethodCall<R, C>(C * obj, 215 Persistent<Function> callback, 216 errorHandler_fn_t errHandler) : 217 AsyncCall_Returning<R>(callback), 218 native_obj(obj), 219 errorHandler(errHandler) {}; 220 }; 221 222 223 /** AsyncAsyncCall is used to wrap returns from NDB Asynchronoous APIs. 224 **/ 225 template <typename R, typename C> 226 class AsyncAsyncCall : public NativeMethodCall<R, C> { 227 public: 228 typedef NativeCodeError * (*errorHandler_fn_t)(R, C *); 229 230 /* Constructor */ 231 AsyncAsyncCall<R, C>(C * obj, Persistent<Function> callback, 232 errorHandler_fn_t errHandler) : 233 NativeMethodCall<R, C>(obj, callback, errHandler) {}; 234 235 /* Methods */ run(void)236 void run(void) {}; 237 }; 238 239 240 /** Alternate second-level template class for calls returning void. 241 No error handling here. 242 **/ 243 template <typename C> 244 class NativeVoidMethodCall : public AsyncCall_Returning<int> { 245 public: 246 /* Member variables */ 247 C * native_obj; 248 249 /* Constructor */ 250 NativeVoidMethodCall<C>(const Arguments &args, int callback_idx) : 251 AsyncCall_Returning<int>(args[callback_idx], 1) /*callback*/ 252 { 253 native_obj = unwrapPointer<C *>(args.Holder()); 254 DEBUG_ASSERT(native_obj != NULL); 255 } 256 }; 257 258 259 /** Base class templated over arguments 260 */ 261 template <typename A0, typename A1, typename A2, typename A3, 262 typename A4, typename A5, typename A6, typename A7> 263 class Call_8_ { 264 public: 265 /* Member variables */ 266 JsValueConverter<A0> arg0converter; A0 arg0; 267 JsValueConverter<A1> arg1converter; A1 arg1; 268 JsValueConverter<A2> arg2converter; A2 arg2; 269 JsValueConverter<A3> arg3converter; A3 arg3; 270 JsValueConverter<A4> arg4converter; A4 arg4; 271 JsValueConverter<A5> arg5converter; A5 arg5; 272 JsValueConverter<A6> arg6converter; A6 arg6; 273 JsValueConverter<A7> arg7converter; A7 arg7; 274 275 /* Constructor */ 276 Call_8_<A0, A1, A2, A3, A4, A5, A6, A7>(const Arguments &args) : arg0converter(args[0])277 arg0converter(args[0]), 278 arg1converter(args[1]), 279 arg2converter(args[2]), 280 arg3converter(args[3]), 281 arg4converter(args[4]), 282 arg5converter(args[5]), 283 arg6converter(args[6]), 284 arg7converter(args[7]) 285 { 286 arg0 = arg0converter.toC(); 287 arg1 = arg1converter.toC(); 288 arg2 = arg2converter.toC(); 289 arg3 = arg3converter.toC(); 290 arg4 = arg4converter.toC(); 291 arg5 = arg5converter.toC(); 292 arg6 = arg6converter.toC(); 293 arg7 = arg7converter.toC(); 294 } 295 }; 296 297 298 template <typename A0, typename A1, typename A2, typename A3, 299 typename A4, typename A5, typename A6> 300 class Call_7_ { 301 public: 302 /* Member variables */ 303 JsValueConverter<A0> arg0converter; A0 arg0; 304 JsValueConverter<A1> arg1converter; A1 arg1; 305 JsValueConverter<A2> arg2converter; A2 arg2; 306 JsValueConverter<A3> arg3converter; A3 arg3; 307 JsValueConverter<A4> arg4converter; A4 arg4; 308 JsValueConverter<A5> arg5converter; A5 arg5; 309 JsValueConverter<A6> arg6converter; A6 arg6; 310 311 /* Constructor */ 312 Call_7_<A0, A1, A2, A3, A4, A5, A6>(const Arguments &args) : arg0converter(args[0])313 arg0converter(args[0]), 314 arg1converter(args[1]), 315 arg2converter(args[2]), 316 arg3converter(args[3]), 317 arg4converter(args[4]), 318 arg5converter(args[5]), 319 arg6converter(args[6]) 320 { 321 arg0 = arg0converter.toC(); 322 arg1 = arg1converter.toC(); 323 arg2 = arg2converter.toC(); 324 arg3 = arg3converter.toC(); 325 arg4 = arg4converter.toC(); 326 arg5 = arg5converter.toC(); 327 arg6 = arg6converter.toC(); 328 } 329 }; 330 331 332 template <typename A0, typename A1, typename A2, typename A3, 333 typename A4, typename A5> 334 class Call_6_ { 335 public: 336 /* Member variables */ 337 JsValueConverter<A0> arg0converter; A0 arg0; 338 JsValueConverter<A1> arg1converter; A1 arg1; 339 JsValueConverter<A2> arg2converter; A2 arg2; 340 JsValueConverter<A3> arg3converter; A3 arg3; 341 JsValueConverter<A4> arg4converter; A4 arg4; 342 JsValueConverter<A5> arg5converter; A5 arg5; 343 344 /* Constructor */ 345 Call_6_<A0, A1, A2, A3, A4, A5>(const Arguments &args) : arg0converter(args[0])346 arg0converter(args[0]), 347 arg1converter(args[1]), 348 arg2converter(args[2]), 349 arg3converter(args[3]), 350 arg4converter(args[4]), 351 arg5converter(args[5]) 352 { 353 arg0 = arg0converter.toC(); 354 arg1 = arg1converter.toC(); 355 arg2 = arg2converter.toC(); 356 arg3 = arg3converter.toC(); 357 arg4 = arg4converter.toC(); 358 arg5 = arg5converter.toC(); 359 } 360 }; 361 362 363 template <typename A0, typename A1, typename A2, typename A3, typename A4> 364 class Call_5_ { 365 public: 366 /* Member variables */ 367 JsValueConverter<A0> arg0converter; A0 arg0; 368 JsValueConverter<A1> arg1converter; A1 arg1; 369 JsValueConverter<A2> arg2converter; A2 arg2; 370 JsValueConverter<A3> arg3converter; A3 arg3; 371 JsValueConverter<A4> arg4converter; A4 arg4; 372 373 /* Constructor */ 374 Call_5_<A0, A1, A2, A3, A4>(const Arguments &args) : arg0converter(args[0])375 arg0converter(args[0]), 376 arg1converter(args[1]), 377 arg2converter(args[2]), 378 arg3converter(args[3]), 379 arg4converter(args[4]) 380 { 381 arg0 = arg0converter.toC(); 382 arg1 = arg1converter.toC(); 383 arg2 = arg2converter.toC(); 384 arg3 = arg3converter.toC(); 385 arg4 = arg4converter.toC(); 386 } 387 }; 388 389 390 template <typename A0, typename A1, typename A2, typename A3> 391 class Call_4_ { 392 public: 393 /* Member variables */ 394 JsValueConverter<A0> arg0converter; A0 arg0; 395 JsValueConverter<A1> arg1converter; A1 arg1; 396 JsValueConverter<A2> arg2converter; A2 arg2; 397 JsValueConverter<A3> arg3converter; A3 arg3; 398 399 /* Constructor */ 400 Call_4_<A0, A1, A2, A3>(const Arguments &args) : arg0converter(args[0])401 arg0converter(args[0]), 402 arg1converter(args[1]), 403 arg2converter(args[2]), 404 arg3converter(args[3]) 405 { 406 arg0 = arg0converter.toC(); 407 arg1 = arg1converter.toC(); 408 arg2 = arg2converter.toC(); 409 arg3 = arg3converter.toC(); 410 } 411 }; 412 413 414 template <typename A0, typename A1, typename A2> 415 class Call_3_ { 416 public: 417 /* Member variables */ 418 JsValueConverter<A0> arg0converter; A0 arg0; 419 JsValueConverter<A1> arg1converter; A1 arg1; 420 JsValueConverter<A2> arg2converter; A2 arg2; 421 422 /* Constructor */ 423 Call_3_<A0, A1, A2>(const Arguments &args) : arg0converter(args[0])424 arg0converter(args[0]), 425 arg1converter(args[1]), 426 arg2converter(args[2]) 427 { 428 arg0 = arg0converter.toC(); 429 arg1 = arg1converter.toC(); 430 arg2 = arg2converter.toC(); 431 } 432 }; 433 434 435 template <typename A0, typename A1> 436 class Call_2_ { 437 public: 438 /* Member variables */ 439 JsValueConverter<A0> arg0converter; A0 arg0; 440 JsValueConverter<A1> arg1converter; A1 arg1; 441 442 /* Constructor */ 443 Call_2_<A0, A1>(const Arguments &args) : arg0converter(args[0])444 arg0converter(args[0]), 445 arg1converter(args[1]) 446 { 447 arg0 = arg0converter.toC(); 448 arg1 = arg1converter.toC(); 449 } 450 }; 451 452 453 template <typename A0> 454 class Call_1_ { 455 public: 456 /* Member variables */ 457 JsValueConverter<A0> arg0converter; A0 arg0; 458 459 /* Constructor */ 460 Call_1_<A0>(const Arguments &args) : arg0converter(args[0])461 arg0converter(args[0]) 462 { 463 arg0 = arg0converter.toC(); 464 } 465 }; 466 467 #endif 468