原生于NodeJS回调

时间:2017-12-01 08:51:35

标签: node.js

我试图编写一个本地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函数

1 个答案:

答案 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

上编写并链接到完整的项目代码