1 #include <node.h>
2 #include <v8.h>
3 #include <thread>  // NOLINT(build/c++11)
4 
5 using node::Environment;
6 using v8::Context;
7 using v8::FunctionCallbackInfo;
8 using v8::HandleScope;
9 using v8::Isolate;
10 using v8::Local;
11 using v8::Maybe;
12 using v8::Object;
13 using v8::String;
14 using v8::Value;
15 
16 static std::thread interrupt_thread;
17 
ScheduleInterrupt(const FunctionCallbackInfo<Value>& args)18 void ScheduleInterrupt(const FunctionCallbackInfo<Value>& args) {
19   Isolate* isolate = args.GetIsolate();
20   HandleScope handle_scope(isolate);
21   Environment* env = node::GetCurrentEnvironment(isolate->GetCurrentContext());
22 
23   interrupt_thread = std::thread([=]() {
24     std::this_thread::sleep_for(std::chrono::seconds(1));
25     node::RequestInterrupt(
26         env,
27         [](void* data) {
28           // Interrupt is called from JS thread.
29           interrupt_thread.join();
30           exit(0);
31         },
32         nullptr);
33   });
34 }
35 
ScheduleInterruptWithJS(const FunctionCallbackInfo<Value>& args)36 void ScheduleInterruptWithJS(const FunctionCallbackInfo<Value>& args) {
37   Isolate* isolate = args.GetIsolate();
38   HandleScope handle_scope(isolate);
39   Environment* env = node::GetCurrentEnvironment(isolate->GetCurrentContext());
40 
41   interrupt_thread = std::thread([=]() {
42     std::this_thread::sleep_for(std::chrono::seconds(1));
43     node::RequestInterrupt(
44         env,
45         [](void* data) {
46           // Interrupt is called from JS thread.
47           interrupt_thread.join();
48           Isolate* isolate = static_cast<Isolate*>(data);
49           HandleScope handle_scope(isolate);
50           Local<Context> ctx = isolate->GetCurrentContext();
51           Local<String> str =
52               String::NewFromUtf8(isolate, "interrupt").ToLocalChecked();
53           // Calling into JS should abort immediately.
54           Maybe<bool> result = ctx->Global()->Set(ctx, str, str);
55           // Should not reach here.
56           if (!result.IsNothing()) {
57             // Called into JavaScript.
58             exit(2);
59           }
60           // Maybe exception thrown.
61           exit(1);
62         },
63         isolate);
64   });
65 }
66 
init(Local<Object> exports)67 void init(Local<Object> exports) {
68   NODE_SET_METHOD(exports, "scheduleInterrupt", ScheduleInterrupt);
69   NODE_SET_METHOD(exports, "ScheduleInterruptWithJS", ScheduleInterruptWithJS);
70 }
71 
72 NODE_MODULE(NODE_GYP_MODULE_NAME, init)
73