-
Notifications
You must be signed in to change notification settings - Fork 293
How to get callbacks from native cpp code. #1171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
what is the relation between your If you have further questions, please elaborate with a specific case, probably with sample code to show what you are trying to achieve. |
Hi @gireeshpunathil , Thanks for your reply. My CPP library is PUB/SUB library.
So, CPP subscriber side will recieve data asynchronously. [Whenever publisher publish] Please let me know if it makes sense? |
@jay11ca39 - thanks. So, you need 2 things, if I understand it right:
Please confirm if this is what you wanted. as pub/sub is already capable of asynchronous data handling, libuv is not required. So all what you need is a mechanism for the native addon to register for being called back. Normal C/C++ semantics, no JS / node specific:
this setup will provide calling back into the addon. Now to go to JS from the addon, use one of the appropriate Call family of methods from nan. Does this sound reasonable to you? |
Hi @gireeshpunathil , Yes, I want the same:
Following are my layers:
What i am trying: Native C++ class
Addon class
I tried the follwing: void AddonClass::addonCallback(AddonClass *pointer) //This object is maintained using std::bind
} When i added Nan::HandleScope scope before getting the handle it is also crashing. Note: I am trying to use event emmiter concept for giving the callbacks to javascript layer. |
@jay11ca39 - there are at least 3 ways to invoke a callback, at high level:
Assuming you are interested in (1), here is the sample code. You can extend it to (2) or (3) as you like: #cat foo.cc #include <nan.h>
Nan::MaybeLocal<v8::Function> fn;
v8::Local<v8::Value> argv[] {Nan::Null()};
Nan::Callback cb;
NAN_METHOD(Register) {
const v8::Local<v8::Function> val = Nan::To<v8::Function>(info[0]).ToLocalChecked();
cb.Reset(val);
}
NAN_METHOD(Invoke) {
cb.Call(1, argv);
}
NAN_MODULE_INIT(Init) {
Nan::Set(target
, Nan::New<v8::String>("register").ToLocalChecked()
, Nan::New<v8::FunctionTemplate>(Register)->GetFunction()
);
Nan::Set(target
, Nan::New<v8::String>("invoke").ToLocalChecked()
, Nan::New<v8::FunctionTemplate>(Invoke)->GetFunction()
);
}
NODE_MODULE(addon, Init) #cat binding.gyp {
"targets": [
{
"xcode_settings": {
"OTHER_CPLUSPLUSFLAGS": [ "'-I../../../node_modules/nan'"],
},
"target_name": "testmodule",
"sources": [ "foo.cc" ]
}
]
} #cat foo.js const tm = require('./testmodule');
function foo() {
console.log('hey, I am a callback!')
console.trace();
}
tm.register(foo);
tm.invoke(); #node-gyp configure build V=1
#cp build/Release/testmodule.node ./testmodule.node
Hope this helps! |
@gireeshpunathil , But when i modified your approch to achieve my scenario it crashed while calling the javascript callback. You are calling javascript callback from here:
I have to call this callback from addon callback which i will register to cpp library :
So, does it mean i can call javascript callback only from NAN_METHOD and not from my addon class other methods? Is there is anything I missed or there is some other mechanism I have to use... |
Sorry for asking many things. As per documentation:
I am trying to achieve this:
|
no, there exist no such restrictions. The crash reason probably is your |
you can send user defined objects through NAN:Callback, but not C++ objects! As the NAN::Callback is destined to JS land, your objects have to be JS objects! sounds reasonable? |
Hello @gireeshpunathil , Following is my addon class: NSubscriber.h
NSubscriber.cpp
|
When I just tried to call the js callback from subscribe method itself it is working well.. like this:
The same thing is crashing when i called from my addon callback [subCallback] which will be called from c++ layer.. |
can you paste here the call stack from the crash? |
Hello @gireeshpunathil Following is the stack trace:
|
|
Hello @gireeshpunathil is gcb part of NSubscriber class? what is nezmq in nezmq::gcb?
I will try to apply.. so as per you if i can make use of scoping in my addon callback to call js callback right? |
right - yes. In addition, also check what (methods) in |
Hello @gireeshpunathil , I applied the changes for scope but it is still crashing. I tried to apply both types of scope handle before acccessing V8 object. But it did not help. I raised the isse in NAN community as well : NAN github issue There it is suggested not use V8 objects in addon class callback. I am little confused .:( |
the suggestion from that thread is not to use v8 objects in a SECOND thread. The basic assumption is that your C++ library routines are executed in the same thread as the JS /addon thread, isn't that the case |
Hello @gireeshpunathil , when cpp library is started by application, it will start a thread internally which will be running continously and when it get any data it will call the application callback.. So, addon thread and cpp library thread are different.. |
looking back at the stack trace (btw I see you have edited the stack trace and changed the frames! - request not to do that, as it mess up the history and confuses reviewers) , it is evident that you are in another thread. Crash reason is evident, as the v8 object heap is not designed for multi-thread concurrent access. |
ok, thanks for the clarification, let me see what can be done. stay tuned. |
#include "uv.h"
static uv_async_t ah;
static uv_thread_t thread;
static void tcb(void* dummy) {
fprintf(stderr, "called in the second thread: 0x%x\n", pthread_self());
uv_async_send(&ah);
}
static void acb(uv_async_t* handle) {
fprintf(stderr, "called back in the main thread: 0x%x\n", pthread_self());
uv_unref((uv_handle_t*)handle);
}
int main() {
uv_async_init(uv_default_loop(), &ah, acb);
uv_thread_create(&thread, tcb, NULL);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
uv_thread_join(&thread);
return 0;
}
In this code, Hope it helps! |
@gireeshpunathil , I am also checking and in case you have any knowledge about about libuv, will it create new threads when i call uv_async_init. As In my case there many be many subscriber so if I have one uv instance per subscriber it will be bottleneck... |
my understanding is that
I just tested with your code using the above approach, and it is working fine. |
Hello @gireeshpunathil , I have tried with libuv approach, as you shown in example.
So it can drop some of my native callback. :( |
@jay11ca39 - great to know you were able to get the callback invoked!
Hope this helps! #include "uv.h"
#include <stdlib.h>
static uv_async_t ah1, ah2;
static uv_thread_t thread1, thread2;
static int sync = 1;
static void tcb1(void* dummy) {
char *data = (char *) malloc(128);
strcpy(data, "tcb1 custom data!");
ah1.data = data;
fprintf(stderr, "thread: %p\n", pthread_self());
uv_async_send(&ah1);
}
static void tcb2(void* dummy) {
fprintf(stderr, "thread: %p\n", pthread_self());
uv_async_send(&ah2);
uv_async_send(&ah2);
uv_async_send(&ah2);
uv_async_send(&ah2);
uv_async_send(&ah2);
uv_async_send(&ah2);
uv_async_send(&ah2);
uv_async_send(&ah2);
}
static void acb1(uv_async_t* handle) {
fprintf(stderr, "acb1 in main thread: %p\n", pthread_self());
fprintf(stderr, "thread data: %s\n", (char *) handle->data);
free(handle->data);
uv_unref((uv_handle_t*)handle);
}
static void acb2(uv_async_t* handle) {
fprintf(stderr, "acb2 in main thread: %p\n", pthread_self());
fprintf(stderr, "thread data: %s\n", (char *) handle->data);
sync = 1;
free(handle->data);
uv_unref((uv_handle_t*)handle);
}
int main() {
uv_async_init(uv_default_loop(), &ah1, acb1);
uv_async_init(uv_default_loop(), &ah2, acb2);
uv_thread_create(&thread1, tcb1, NULL);
uv_thread_create(&thread2, tcb2, NULL);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
uv_thread_join(&thread1);
uv_thread_join(&thread2);
return 0;
} ./a.out
|
Hello @gireeshpunathil , I have one last query:
I am using mutex lock mechanism i.e. once I get callback in my native addon callback I will call uv_async_send(uvAsyncHandle) and I will lock till js callback is called. My doubt is about UV library: will it be internally synchronized throughout the process. I mean in case of many native threads can send callbacks to different subscriber in the addon layer and from there it has to call uv_async_send() to send it to js thread. will it be done one at a time throughout the process. |
Hope this helps. |
@jay11ca39 - is your problem resolved? Is there anything outstanding on this thread? |
Thanks @gireeshpunathil .. The issue is being resolved. Thank you very much for your help and support. |
I am new to Native addon concept. I am using NAN to build my native addon.
Following are my layers:
I have some query regarding callback mechanism:
How my addon layer will get the callbacks from Native layer [C++ library].
Do i have to use libuv to get callbacks from c++ layer or there are other ways to do so?
Thanks in advance.
The text was updated successfully, but these errors were encountered: