1 #include <node.h>
2 #include <v8.h>
3 #include <uv.h>
4
5 struct 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
DoAsync(uv_work_t * r)14 void 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
21 template <bool use_makecallback>
AfterAsync(uv_work_t * r)22 void 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
60 template <bool use_makecallback>
Method(const v8::FunctionCallbackInfo<v8::Value> & args)61 void 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
init(v8::Local<v8::Object> exports,v8::Local<v8::Object> module)81 void 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
86 NODE_MODULE(NODE_GYP_MODULE_NAME, init)
87