-
Notifications
You must be signed in to change notification settings - Fork 465
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
Passing char pointer #501
Comments
You can use Uint8Array instead of Buffer.
Cpp:
Hope this helps. |
Thanks a lot. What should we do for *int and *function pointers?
Functions:
|
You can use TypedArrayOf |
The code examples link you shared points to the previous link. However, I tried the following for uint32_t pointer case and it worked fine: In JS:
In C++:
Can you point to any docs for function pointer? Also, TypedArrays were introduced in node 8, is it possible to use buffer instead so that it works with older versions too. |
I updated the link. All resources are provided in this repos README. If you need compatibility with older nodejs versions, you will have to use Native Abstractions of Node (NAN) api AFAIK. |
The callback example doesn't fit the use case. It is calling the callback function immediately. But I need to call the callback, when the internal c callback has finished (inside c callback). So it seems I need to store some global variables.
Is there any way to avoid global variables, and in case user sets many callbacks I will need to store them in a global list. |
@adnan-kamili you should probably look at the AsyncWorker functionality. |
Hi @mhdawson , Thanks, I succeeded in implementing my use case, can you please have a look in case I did something wrong: class CallbackWrapper : public Napi::AsyncWorker
{
public:
CallbackWrapper(Napi::Function &callback) : Napi::AsyncWorker(callback)
{
}
uint32_t status;
private:
void Execute()
{
}
void OnOK()
{
Napi::HandleScope scope(Env());
Callback().Call({Napi::Number::New(Env(), status)});
}
}; I had to keep a map of AsyncWorker because user can register many callbacks in my case: map<string, CallbackWrapper*> MyCallbacks;
void MyCallback(uint32_t status)
{
MyCallbacks[Key]->status = status;
MyCallbacks[Key]->Queue();
}
Napi::Value setMyCallback(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
// some validations
Napi::Function callback = info[0].As<Napi::Function>();
LicenseCallbacks[Key] = new CallbackWrapper(callback);
LicenseCallbacks[Key]->SuppressDestruct(); // needed because callback is invoked periodically by the C++ library
return Napi::Number::New(env, SetCallback(MyCallback));
} |
I think one issue is that it looks like you might be re-using the AsyncWorker. From the N-API docs (which is what the class in node-addon-api uses under the covers) you should only call queue once for a given instance. https://nodejs.org/api/n-api.html#n_api_napi_queue_async_work. I'm also guessing that you must be calling "MyCallback" on a thread other than the main thread. If you have your own threads in addition to the main JS thread then you should look at using https://nodejs.org/api/n-api.html#n_api_asynchronous_thread_safe_function_calls (we are working on landing a wrapper for these in node-addon-api but it has not yet landed - > #442) |
Yes, the MyCallback() function is invoked at an interval repeatedly by the C library from a separate thread, so the queue() function is executed multiple times. I tested this on Windows, Mac, and Linux, and it works fine. I guess it should be fine because I have no code in the execute function. |
@adnan-kamili I think you may just be getting "lucky" or "unlucky" depending on how you look at it since its documented that it will not necessarily work. @gabrielschulhof can you fact check me on this? |
@mhdawson yes, @adnan-kamili you mentioned that you need to create a binding for a C function that accepts a function pointer with the following signature: typedef void (int *CallbackType)(uint32_t);
^^^ AFAIK having the So, I'm assuming the API looks like this: typedef void(*CallbackType)(uint32_t);
void give_me_an_integer_later(CallbackType cb); it becomes crucially important to know whether uint32_t last_result;
static void TheCallback(uint32_t result) {
last_result = result;
}
static Napi::Value bind_give_me_an_integer_later(
const Napi::CallbackInfo& info) {
give_me_an_integer_later(TheCallback);
info[0]
.As<Napi::Function>()
.Call({Napi::Number::New(info.Env(), last_result});
} However, if
This latter part requires that the C API guarantee some order in which it calls The situation in which static void TheCallback(uint32_t value, Napi::FunctionReference ref) {
} which this other function would call, passing through the Doing FFI is pretty complicated, but the only way to go when the API is not of this form: void give_me_an_integer_later(void (*callback)(uint32_t value, void* data), void* data);
I have an example of using FFI:
In the example, |
Thanks a lot for such a detailed answer. In my case, the callback is not invoked immediately but later by the C library in a separate thread. And this callback is not invoked once but many times at a specific interval. Initially, we did use node-ffi to create a wrapper, but node-ffi is not supported for arm architecture and Callback functions segfault on Alpine Linux. Hence, we decided to go with N-API, and now it works on all the platforms/architecture we support. Instead of using AsyncWorker for implementing our use-case, we did try function references by storing a function reference list globally, but it always segfaulted. We could only get it working using AsyncWorker. |
@adnan-kamili thanks for your follow-up! I'm glad to hear you were able to find a solution! |
@gabrielschulhof I'm concerned that the use of AsyncWorker is only working by "good or bad" luck and @adnan-kamili should probably be using the threadsafe functions instead. |
@mhdawson @adnan-kamili I agree that there is no guarantee in the above implementation of In order to ensure correctness, a semaphore would have to be associated with each A solution thus modified would be correct in the sense that no secondary thread ends up making calls into the main thread and there are no race conditions, however, it would be significantly more resource-intensive than it needed to be, because creating so many Assuming I have gauged the situation correctly, I believe @mhdawson is right in that a thread-safe function would better suit your needs, because a TSFN is designed to convey multiple calls from multiple threads into JavaScript via a marshalling function that runs on the main thread. #442 has just landed, so the TSFN C++ wrapper should be available in the next release of node-addon-api 👍 |
Closing out since I think the original question was answered and the discussion closed out. Please let us know if that is not the right thing to do. |
I have a simple C function with the following signature:
int GetMetadata(const char* key, char* value, size_t length);
I want to wrap this function using napi. I tried the following:
From Javascript, I would be passing in a buffer of length 256. How do I assign metadataValue to buffer passed in through JS?
The text was updated successfully, but these errors were encountered: