原生的NodeJScallback

我正在尝试编写一个本地的NodeJS模块,它将定期从循环中进行callback。 我想我已经回到了主线程所需要的libuv位,以便进行callback,但是在进行callback的时候,它仍然会与一个sigsegv一起崩溃。

test_sbio.cpp:

#include <node.h> #include "SBIONative.h" namespace sbio { using v8::Local; using v8::Object; void InitAll(Local<Object> exports) { SBIONative::Init(exports); } NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll) } 

SBIONative.h:

 #ifndef SBIONative_H #define SBIONative_H #include <iostream> #include <unistd.h> #include <uv.h> #include <node.h> #include <node_object_wrap.h> namespace sbio { class SBIONative : public node::ObjectWrap { public: static void Init(v8::Local<v8::Object> exports); private: explicit SBIONative(); ~SBIONative(); static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static v8::Persistent<v8::Function> constructor; static void Start(const v8::FunctionCallbackInfo<v8::Value>& args); static void Stop(const v8::FunctionCallbackInfo<v8::Value>& args); static void loop(void *arg); static void asyncmsg(uv_async_t* handle); v8::Persistent<v8::Function> cb; bool run_; uv_async_t async; uv_thread_t event_loop; }; } #endif 

SBIONative.cpp:

 #include <SBIONative.h> namespace sbio { using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::HandleScope; using v8::Local; using v8::Number; using v8::Object; using v8::Persistent; using v8::String; using v8::Value; Persistent<Function> SBIONative::constructor; SBIONative::SBIONative() { } SBIONative::~SBIONative() { } void SBIONative::Init(Local<Object> exports) { Isolate* isolate = exports->GetIsolate(); // Prepare constructor template Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New); tpl->SetClassName(String::NewFromUtf8(isolate, "SBIONative")); tpl->InstanceTemplate()->SetInternalFieldCount(2); // Prototype NODE_SET_PROTOTYPE_METHOD(tpl, "start", Start); NODE_SET_PROTOTYPE_METHOD(tpl, "stop", Stop); constructor.Reset(isolate, tpl->GetFunction()); exports->Set(String::NewFromUtf8(isolate, "SBIONative"), tpl->GetFunction()); } void SBIONative::New(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); if (args.IsConstructCall()) { // Invoked as constructor: `new MyObject(...)` SBIONative* obj = new SBIONative(); obj->Wrap(args.This()); args.GetReturnValue().Set(args.This()); uv_loop_t* loop = uv_default_loop(); uv_async_init(loop, &obj->async, asyncmsg); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local<Value> argv[argc] = { args[0] }; Local<Context> context = isolate->GetCurrentContext(); Local<Function> cons = Local<Function>::New(isolate, constructor); Local<Object> result = cons->NewInstance(context, argc, argv).ToLocalChecked(); args.GetReturnValue().Set(result); } } void SBIONative::Start(const FunctionCallbackInfo<Value>& args) { std::cout << "Start\n"; Isolate* isolate = args.GetIsolate(); SBIONative* obj = ObjectWrap::Unwrap<SBIONative>(args.Holder()); obj->run_ = true; Local<Function> callback = Local<v8::Function>::Cast(args[0]); obj->cb.Reset(isolate, callback); uv_thread_create(&obj->event_loop, SBIONative::loop, (void*)obj); } void SBIONative::Stop(const FunctionCallbackInfo<Value>& args) { std::cout << "Stop\n"; SBIONative* obj = ObjectWrap::Unwrap<SBIONative>(args.Holder()); obj->run_ = false; uv_close((uv_handle_t*) &obj->async, NULL); } void SBIONative::loop(void *arg) { SBIONative* obj = (SBIONative*)arg; while(obj->run_) { usleep(1 * 1000 * 1000); std::cout << "loop\n"; obj->async.data = &obj->cb; uv_async_send(&obj->async); } std::cout << "after loop" << std::endl; } void SBIONative::asyncmsg(uv_async_t* handle) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope scope(isolate); Local<Value> argv[] = { v8::String::NewFromUtf8(isolate, "Hello world") }; //TODO This breaks here ((v8::Function*)handle->data)->Call(isolate->GetCurrentContext()->Global(), 1, argv); std::cout << "callback" << std::endl; } } 

如果我在Mac或Linux上构build它,这将失败。 迄今为止我最好的猜测是将callback存储在对象中,或将其转换为asyncmsg函数

今天又有了一个这样的工作,我有一个工作的解决scheme。 诀窍是使用Nan而不是尝试和推出我自己的本地接口。

addon.c:

 #include <nan.h> #include "test.h" void InitAll(v8::Local<v8::Object> exports) { test::Test::Init(exports); } NODE_MODULE(addon, InitAll) 

test.h:

 #ifndef TEST_H #define TEST_H #include <nan.h> #include <iostream> #include <unistd.h> namespace test { class Test : public Nan::ObjectWrap { public: static void Init(v8::Local<v8::Object> exports); private: explicit Test(); ~Test(); static void New(const Nan::FunctionCallbackInfo<v8::Value>& info); static void Start(const Nan::FunctionCallbackInfo<v8::Value>& info); static void Stop(const Nan::FunctionCallbackInfo<v8::Value>& info); static void loop(void *arg); static void asyncmsg(uv_async_t* handle); static Nan::Persistent<v8::Function> constructor; bool run_; Nan::Callback* callback; uv_async_t async; uv_thread_t event_loop; }; } #endif 

TEST.CPP:

 #include "test.h" namespace test { Nan::Persistent<v8::Function> Test::constructor; Test::Test(){} Test::~Test(){} void Test::Init(v8::Local<v8::Object> exports) { Nan::HandleScope scope; v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New); tpl->SetClassName(Nan::New("Test").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Nan::SetPrototypeMethod(tpl, "start", Start); Nan::SetPrototypeMethod(tpl, "stop", Stop); constructor.Reset(tpl->GetFunction()); exports->Set(Nan::New("Test").ToLocalChecked(), tpl->GetFunction()); } void Test::New(const Nan::FunctionCallbackInfo<v8::Value>& info) { if (info.IsConstructCall()) { // Invoked as constructor: `new Test(...)` test::Test* obj = new test::Test(); obj->Wrap(info.This()); info.GetReturnValue().Set(info.This()); uv_loop_t* loop = uv_default_loop(); uv_async_init(loop, &obj->async, asyncmsg); } else { // Invoked as plain function `Test(...)`, turn into construct call. const int argc = 1; v8::Local<v8::Value> argv[argc] = { info[0] }; v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor); info.GetReturnValue().Set(cons->NewInstance(argc, argv)); } } void Test::Start(const Nan::FunctionCallbackInfo<v8::Value>& info) { Test* obj = ObjectWrap::Unwrap<Test>(info.Holder()); obj->callback = new Nan::Callback(info[0].As<v8::Function>()); obj->run_ = true; uv_thread_create(&obj->event_loop, Test::loop, (void*)obj); } void Test::Stop(const Nan::FunctionCallbackInfo<v8::Value>& info) { Test* obj = ObjectWrap::Unwrap<Test>(info.Holder()); obj->run_ = false; } void Test::loop(void *arg) { Test* obj = (Test*)arg; while(obj->run_) { usleep(1 * 1000 * 1000); obj->async.data = obj->callback; uv_async_send(&obj->async); } uv_close((uv_handle_t*) &obj->async, NULL); } void Test::asyncmsg(uv_async_t* handle) { Nan::HandleScope scope; v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::Local<v8::Value> argv[] = { v8::String::NewFromUtf8(isolate, "Loop Callback") }; ((Nan::Callback*)handle->data)->Call(1,argv); } } 

在这里写上并链接到github上的完整项目代码