1#include <node.h> 2#include <v8.h> 3#include <uv.h> 4 5struct async_req { 6 uv_work_t req; 7 int input; 8 int output; 9 v8::Isolate* isolate; 10 v8::Global<v8::Function> callback; 11 node::async_context context; 12}; 13 14void DoAsync(uv_work_t* r) { 15 async_req* req = reinterpret_cast<async_req*>(r->data); 16 // Simulate CPU intensive process... 17 uv_sleep(1000); 18 req->output = req->input * 2; 19} 20 21template <bool use_makecallback> 22void AfterAsync(uv_work_t* r) { 23 async_req* req = reinterpret_cast<async_req*>(r->data); 24 v8::Isolate* isolate = req->isolate; 25 v8::HandleScope scope(isolate); 26 27 v8::Local<v8::Value> argv[2] = { 28 v8::Null(isolate), 29 v8::Integer::New(isolate, req->output) 30 }; 31 32 v8::TryCatch try_catch(isolate); 33 34 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global(); 35 v8::Local<v8::Function> callback = 36 v8::Local<v8::Function>::New(isolate, req->callback); 37 38 if (use_makecallback) { 39 v8::Local<v8::Value> ret = 40 node::MakeCallback(isolate, global, callback, 2, argv, req->context) 41 .ToLocalChecked(); 42 // This should be changed to an empty handle. 43 assert(!ret.IsEmpty()); 44 } else { 45 callback->Call(isolate->GetCurrentContext(), 46 global, 2, argv).ToLocalChecked(); 47 } 48 49 // None of the following operations should allocate handles into this scope. 50 v8::SealHandleScope seal_handle_scope(isolate); 51 // cleanup 52 node::EmitAsyncDestroy(isolate, req->context); 53 delete req; 54 55 if (try_catch.HasCaught()) { 56 node::FatalException(isolate, try_catch); 57 } 58} 59 60template <bool use_makecallback> 61void Method(const v8::FunctionCallbackInfo<v8::Value>& args) { 62 v8::Isolate* isolate = args.GetIsolate(); 63 64 async_req* req = new async_req; 65 req->req.data = req; 66 67 req->input = args[0].As<v8::Integer>()->Value(); 68 req->output = 0; 69 req->isolate = isolate; 70 req->context = node::EmitAsyncInit(isolate, v8::Object::New(isolate), "test"); 71 72 v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(args[1]); 73 req->callback.Reset(isolate, callback); 74 75 uv_queue_work(node::GetCurrentEventLoop(isolate), 76 &req->req, 77 DoAsync, 78 (uv_after_work_cb)AfterAsync<use_makecallback>); 79} 80 81void init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module) { 82 NODE_SET_METHOD(exports, "runCall", Method<false>); 83 NODE_SET_METHOD(exports, "runMakeCallback", Method<true>); 84} 85 86NODE_MODULE(NODE_GYP_MODULE_NAME, init) 87