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