Skip to content

Commit

Permalink
Cpp rewrite (#218)
Browse files Browse the repository at this point in the history
* replace static function with static method
* remove using statements
* underscore suffix private members
* inline begin_poll
* fix `make perf`
* make PollCtx subclass Nan::AsyncWorker
   This allows PollCtx to leave the lifetime management of the callback to
   AsyncWorker, and allows us to use the AsyncWorker's async_resource.

* No change in `make perf` was observed, though it's a little noisy.

We must implement the pure virtual function interface for Exectute(),
but I'm not sure what it's for.

Also, I believe that ~AsyncWorker() deletes the passed callback, as all
of the examples show calls to new Nan::Callback().

Fixes #209
  • Loading branch information
nickdesaulniers authored and reqshark committed Sep 3, 2019
1 parent fa47cc6 commit a4cdcf5
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 77 deletions.
2 changes: 1 addition & 1 deletion perf/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ exports.createMsg = function(msgType, sz) {
var buf;
switch (msgType) {
case '--buffer':
buf = Buffer_alloc(sz, 'o');
buf = buffer_alloc(sz, 'o');
break;
case '--string':
buf = new Array(sz + 1).join('o');
Expand Down
67 changes: 31 additions & 36 deletions src/node_nanomsg.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,11 @@
#include "tcp.h"
#include "ws.h"

using v8::Function;
using v8::FunctionTemplate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;

NAN_METHOD(Socket) {
int domain = Nan::To<int>(info[0]).FromJust();
int protocol = Nan::To<int>(info[1]).FromJust();

info.GetReturnValue().Set(Nan::New<Number>(nn_socket(domain, protocol)));
info.GetReturnValue().Set(Nan::New<v8::Number>(nn_socket(domain, protocol)));
}

NAN_METHOD(Close) {
Expand All @@ -34,7 +26,7 @@ NAN_METHOD(Close) {
rc = nn_close(s);
} while (rc < 0 && errno == EINTR);

info.GetReturnValue().Set(Nan::New<Number>(rc));
info.GetReturnValue().Set(Nan::New<v8::Number>(rc));
}

NAN_METHOD(Setopt) {
Expand All @@ -43,7 +35,7 @@ NAN_METHOD(Setopt) {
int option = Nan::To<int>(info[2]).FromJust();
int optval = Nan::To<int>(info[3]).FromJust();

info.GetReturnValue().Set(Nan::New<Number>(
info.GetReturnValue().Set(Nan::New<v8::Number>(
nn_setsockopt(s, level, option, &optval, sizeof(optval))));
}

Expand All @@ -56,7 +48,7 @@ NAN_METHOD(Getopt) {

// check if the function succeeds
if (nn_getsockopt(s, level, option, &optval, &optsize) == 0) {
info.GetReturnValue().Set(Nan::New<Number>(optval));
info.GetReturnValue().Set(Nan::New<v8::Number>(optval));
}
}

Expand All @@ -66,42 +58,42 @@ NAN_METHOD(Chan) {
int option = Nan::To<int>(info[1]).FromJust();
Nan::Utf8String str(info[2]);

info.GetReturnValue().Set(
Nan::New<Number>(nn_setsockopt(s, level, option, *str, str.length())));
info.GetReturnValue().Set(Nan::New<v8::Number>(
nn_setsockopt(s, level, option, *str, str.length())));
}

NAN_METHOD(Bind) {
int s = Nan::To<int>(info[0]).FromJust();
Nan::Utf8String addr(info[1]);

info.GetReturnValue().Set(Nan::New<Number>(nn_bind(s, *addr)));
info.GetReturnValue().Set(Nan::New<v8::Number>(nn_bind(s, *addr)));
}

NAN_METHOD(Connect) {
int s = Nan::To<int>(info[0]).FromJust();
Nan::Utf8String addr(info[1]);

info.GetReturnValue().Set(Nan::New<Number>(nn_connect(s, *addr)));
info.GetReturnValue().Set(Nan::New<v8::Number>(nn_connect(s, *addr)));
}

NAN_METHOD(Shutdown) {
int s = Nan::To<int>(info[0]).FromJust();
int how = Nan::To<int>(info[1]).FromJust();

info.GetReturnValue().Set(Nan::New<Number>(nn_shutdown(s, how)));
info.GetReturnValue().Set(Nan::New<v8::Number>(nn_shutdown(s, how)));
}

NAN_METHOD(Send) {
int s = Nan::To<int>(info[0]).FromJust();
int flags = Nan::To<int>(info[2]).FromJust();

if (node::Buffer::HasInstance(info[1])) {
info.GetReturnValue().Set(Nan::New<Number>(nn_send(
info.GetReturnValue().Set(Nan::New<v8::Number>(nn_send(
s, node::Buffer::Data(info[1]), node::Buffer::Length(info[1]), flags)));
} else {
Nan::Utf8String str(info[1]);
info.GetReturnValue().Set(
Nan::New<Number>(nn_send(s, *str, str.length(), flags)));
Nan::New<v8::Number>(nn_send(s, *str, str.length(), flags)));
}
}

Expand All @@ -118,10 +110,10 @@ NAN_METHOD(Recv) {
int len = nn_recv(s, &buf, NN_MSG, flags);

if (len > -1) {
Local<Object> h = Nan::NewBuffer(buf, len, fcb, 0).ToLocalChecked();
v8::Local<v8::Object> h = Nan::NewBuffer(buf, len, fcb, 0).ToLocalChecked();
info.GetReturnValue().Set(h);
} else {
info.GetReturnValue().Set(Nan::New<Number>(len));
info.GetReturnValue().Set(Nan::New<v8::Number>(len));
}
}

Expand All @@ -131,16 +123,17 @@ NAN_METHOD(SymbolInfo) {
int ret = nn_symbol_info(s, &prop, sizeof(prop));

if (ret > 0) {
Local<Object> obj = Nan::New<Object>();
v8::Local<v8::Object> obj = Nan::New<v8::Object>();
Nan::Set(obj, Nan::New("value").ToLocalChecked(),
Nan::New<Number>(prop.value));
Nan::Set(obj, Nan::New("ns").ToLocalChecked(), Nan::New<Number>(prop.ns));
Nan::New<v8::Number>(prop.value));
Nan::Set(obj, Nan::New("ns").ToLocalChecked(),
Nan::New<v8::Number>(prop.ns));
Nan::Set(obj, Nan::New("type").ToLocalChecked(),
Nan::New<Number>(prop.type));
Nan::New<v8::Number>(prop.type));
Nan::Set(obj, Nan::New("unit").ToLocalChecked(),
Nan::New<Number>(prop.unit));
Nan::New<v8::Number>(prop.unit));
Nan::Set(obj, Nan::New("name").ToLocalChecked(),
Nan::New<String>(prop.name).ToLocalChecked());
Nan::New<v8::String>(prop.name).ToLocalChecked());
info.GetReturnValue().Set(obj);
} else if (ret != 0) {
Nan::ThrowError(nn_strerror(nn_errno()));
Expand All @@ -153,10 +146,11 @@ NAN_METHOD(Symbol) {
const char *ret = nn_symbol(s, &val);

if (ret) {
Local<Object> obj = Nan::New<Object>();
Nan::Set(obj, Nan::New("value").ToLocalChecked(), Nan::New<Number>(val));
v8::Local<v8::Object> obj = Nan::New<v8::Object>();
Nan::Set(obj, Nan::New("value").ToLocalChecked(),
Nan::New<v8::Number>(val));
Nan::Set(obj, Nan::New("name").ToLocalChecked(),
Nan::New<String>(ret).ToLocalChecked());
Nan::New<v8::String>(ret).ToLocalChecked());
info.GetReturnValue().Set(obj);
} else {
// symbol index out of range
Expand All @@ -178,7 +172,7 @@ NAN_METHOD(Device) {
Nan::ThrowError(nn_strerror(nn_errno()));
}

NAN_METHOD(Errno) { info.GetReturnValue().Set(Nan::New<Number>(nn_errno())); }
NAN_METHOD(Errno) { info.GetReturnValue().Set(Nan::New<v8::Number>(nn_errno())); }

NAN_METHOD(Err) {
info.GetReturnValue().Set(Nan::New(nn_strerror(nn_errno())).ToLocalChecked());
Expand All @@ -187,7 +181,8 @@ NAN_METHOD(Err) {
NAN_METHOD(PollSocket) {
const int s = Nan::To<int>(info[0]).FromJust();
const bool is_sender = Nan::To<bool>(info[1]).FromJust();
const Local<Function> cb = info[2].As<Function>();
Nan::Callback *cb = new Nan::Callback(
Nan::To<v8::Function>(info[2]).ToLocalChecked());
PollCtx *context = new PollCtx(s, is_sender, cb);
info.GetReturnValue().Set(PollCtx::WrapPointer(context, sizeof context));
}
Expand Down Expand Up @@ -228,7 +223,7 @@ class NanomsgDeviceWorker : public Nan::AsyncWorker {
void HandleOKCallback() {
Nan::HandleScope scope;

Local<Value> argv[] = { Nan::New<Number>(err) };
v8::Local<v8::Value> argv[] = { Nan::New<v8::Number>(err) };

callback->Call(1, argv, async_resource);
};
Expand All @@ -243,14 +238,14 @@ class NanomsgDeviceWorker : public Nan::AsyncWorker {
NAN_METHOD(DeviceWorker) {
int s1 = Nan::To<int>(info[0]).FromJust();
int s2 = Nan::To<int>(info[1]).FromJust();
Nan::Callback *callback = new Nan::Callback(info[2].As<Function>());
Nan::Callback *callback = new Nan::Callback(info[2].As<v8::Function>());

Nan::AsyncQueueWorker(new NanomsgDeviceWorker(callback, s1, s2));
}

#define EXPORT_METHOD(C, S) \
Nan::Set(C, Nan::New(#S).ToLocalChecked(), \
Nan::GetFunction(Nan::New<FunctionTemplate>(S)).ToLocalChecked());
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(S)).ToLocalChecked());

NAN_MODULE_INIT(InitAll) {
Nan::HandleScope scope;
Expand Down Expand Up @@ -284,7 +279,7 @@ NAN_MODULE_INIT(InitAll) {
break;
}
Nan::Set(target, Nan::New(symbol_name).ToLocalChecked(),
Nan::New<Number>(value));
Nan::New<v8::Number>(value));
}
}

Expand Down
43 changes: 15 additions & 28 deletions src/poll_ctx.cc
Original file line number Diff line number Diff line change
@@ -1,48 +1,35 @@
#include "nn.h"
#include "poll_ctx.h"

using v8::Function;
using v8::Local;
using v8::Number;
using v8::Value;

static void NanomsgReadable(uv_poll_t* req, int /* status */, int events) {
const PollCtx* const context = static_cast<PollCtx*>(req->data);
if (events & UV_READABLE) {
context->invoke_callback(events);
}
void PollCtx::on_readable(uv_poll_t* req, int /* status */, int events) {
if (!(events & UV_READABLE))
return;
Nan::HandleScope scope;
v8::Local<v8::Value> argv[] = { Nan::New<v8::Number>(events) };
PollCtx* ctx = reinterpret_cast<PollCtx*>(req->data);
ctx->callback->Call(1, argv, ctx->async_resource);
}

void PollCtx::begin_poll (const int s, const bool is_sender) {
PollCtx::PollCtx (const int s, const bool is_sender,
Nan::Callback* cb): Nan::AsyncWorker(cb, "nanomsg::PollCtx") {
size_t siz = sizeof(uv_os_sock_t);
uv_os_sock_t sockfd;
nn_getsockopt(s, NN_SOL_SOCKET, is_sender ? NN_SNDFD : NN_RCVFD, &sockfd,
&siz);
if (sockfd != 0) {
uv_poll_init_socket(uv_default_loop(), &poll_handle, sockfd);
uv_poll_start(&poll_handle, UV_READABLE, NanomsgReadable);
}
}
if (!sockfd)
return;

PollCtx::PollCtx (const int s, const bool is_sender,
const Local<Function> cb): callback(cb) {
// TODO: maybe container_of can be used instead?
// that would save us this assignment, and ugly static_cast hacks.
poll_handle.data = this;
begin_poll(s, is_sender);
}

void PollCtx::invoke_callback (const int events) const {
Nan::HandleScope scope;
Local<Value> argv[] = { Nan::New<Number>(events) };
callback.Call(1, argv);
uv_poll_init_socket(uv_default_loop(), &poll_handle, sockfd);
uv_poll_start(&poll_handle, UV_READABLE, PollCtx::on_readable);
}

// Nan will invoke this once it's done with the Buffer, in case we wanted to
// free ptr. In this case, ptr is a PollCtx that we're not done with and don't
// want to free yet (not until PollStop is invoked), so we do nothing.
static void wrap_pointer_cb(char * /* data */, void * /* hint */) {}

Local<Value> PollCtx::WrapPointer (void* ptr, size_t length) {
v8::Local<v8::Value> PollCtx::WrapPointer (void* ptr, size_t length) {
return Nan::NewBuffer(static_cast<char *>(ptr), length, wrap_pointer_cb, 0)
.ToLocalChecked();
}
Expand Down
20 changes: 8 additions & 12 deletions src/poll_ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@

#include <nan.h>

class PollCtx {
private:
const Nan::Callback callback;
uv_os_sock_t sockfd; // for libnanomsg
void begin_poll (const int s, const bool is_sender);
public:
uv_poll_t poll_handle; // for libuv
PollCtx (const int s, const bool is_sender,
const v8::Local<v8::Function> cb);
void invoke_callback (const int events) const;
static v8::Local<v8::Value> WrapPointer (void* ptr, size_t length);
static PollCtx* UnwrapPointer (v8::Local<v8::Value> buffer);
class PollCtx : public Nan::AsyncWorker {
static void on_readable(uv_poll_t* req, int /* status */, int events);
public:
uv_poll_t poll_handle; // for libuv
PollCtx (const int s, const bool is_sender, Nan::Callback* cb);
void Execute () /* override */ {};
static v8::Local<v8::Value> WrapPointer (void* ptr, size_t length);
static PollCtx* UnwrapPointer (v8::Local<v8::Value> buffer);
};

0 comments on commit a4cdcf5

Please sign in to comment.