1#include <node.h>
2#include <v8.h>
3#include <thread>  // NOLINT(build/c++11)
4
5using node::Environment;
6using v8::Context;
7using v8::FunctionCallbackInfo;
8using v8::HandleScope;
9using v8::Isolate;
10using v8::Local;
11using v8::Maybe;
12using v8::Object;
13using v8::String;
14using v8::Value;
15
16static std::thread interrupt_thread;
17
18void 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
36void 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
67void init(Local<Object> exports) {
68  NODE_SET_METHOD(exports, "scheduleInterrupt", ScheduleInterrupt);
69  NODE_SET_METHOD(exports, "ScheduleInterruptWithJS", ScheduleInterruptWithJS);
70}
71
72NODE_MODULE(NODE_GYP_MODULE_NAME, init)
73