我试图编写一个本地NodeJS模块,它将定期从循环中进行回调。我认为我已经掌握了回到主线程进行回调所需的libuv位,但它仍然会在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上构建它,它会在同一个地方失败。我迄今为止最好的猜测是在对象中存储回调或将其转换为asyncmsg
函数
答案 0 :(得分:1)
今天再次参加此活动后,我找到了一个有效的解决方案。诀窍是使用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 here
上编写并链接到完整的项目代码