Skip to content
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

ThreadSafeFunction(napi_threadsafe_function) works badly with BlockingCall() #556

Closed
o2genum opened this issue Oct 5, 2019 · 6 comments · Fixed by #580
Closed

ThreadSafeFunction(napi_threadsafe_function) works badly with BlockingCall() #556

o2genum opened this issue Oct 5, 2019 · 6 comments · Fixed by #580

Comments

@o2genum
Copy link

o2genum commented Oct 5, 2019

When a ThreadSafeFunction instance is created from napi_threadsafe_function, its BlockingCall method doesn't work properly:

  • The passed callback is ignored, but still required by the method signature (the one supplied with napi_create_threadsafe_function is used)
  • The passed data pointer is incorrect for some reason. napi_call_threadsafe_function works fine.

I'm doing this because I want to napi_unref_threadsafe_function without using all the verbose C APIs.

@KevinEady
Copy link
Contributor

Hello @o2genum ,

Can you post some code that you are using? Here's some code using BlockingCall() in all three overloads:

auto callback = [](Env env, Function jsCallback, int* data) {
jsCallback.Call({ Number::New(env, *data) });
};
switch (info->type) {
case ThreadSafeFunctionInfo::DEFAULT:
status = tsfn.BlockingCall();
break;
case ThreadSafeFunctionInfo::BLOCKING:
status = tsfn.BlockingCall(&ints[index], callback);
break;
case ThreadSafeFunctionInfo::NON_BLOCKING:
status = tsfn.NonBlockingCall(&ints[index], callback);
break;
}

We have two tests: one using BlockingCall with no callback or data, and one using BlockingCall with data and callback, passing an int* to callback, which receives that value.

void entryWithTSFN(ThreadSafeFunction tsfn, int threadId) {
std::this_thread::sleep_for(std::chrono::milliseconds(std::rand() % 100 + 1));
tsfn.BlockingCall( [=](Napi::Env env, Function callback) {
callback.Call( { Number::New(env, static_cast<double>(threadId))});
});
tsfn.Release();
}

And here we use BlockingCall() with only callback and no data.

@KevinEady
Copy link
Contributor

Ahh, I am sorry, I misunderstood your issue. Using the node-addon-api with a pre-constructed napi_threadsafe_function fails. I will take a look. Thanks!

@o2genum
Copy link
Author

o2genum commented Oct 7, 2019

Nice! By the way, I want to note I could have done without wrapping TSFN from C API into C++ API one if there was a way to call napi_unref_threadsafe_function from C++ API, to prevent the TSFN from keeping event loop alive.

KevinEady added a commit to KevinEady/node-addon-api that referenced this issue Oct 9, 2019
@KevinEady
Copy link
Contributor

Hi @o2genum ,

Yeah, so I'm not sure how we can wrap an existing napi_tsfn in a new ThreadSafeFunction... And yep, the main problem is with how the TSFN is not a "1:1 wrapper" with napi_tsfn functions I suppose.

When creating a node-addon-api TSFN, you do not specify a call_js_cb parameter like you do in underlying napi_create_threadsafe_function. Instead, this is passed as the optional Callback parameter in the [Non]BlockingCall method. (In the TSFN wrapper, this function is used, and the optional Callback and Data are passed as a wrapped function pointer inside the void* data pointer)

I'll need to discuss this with the napi team for a good approach / if it's even possible.

In the mean time, we have two PRs that can solve your problem:

@KevinEady
Copy link
Contributor

KevinEady commented Oct 15, 2019

Hi @gabrielschulhof / @mhdawson ,

I wanted to bring this up at yesterday's meeting but alas...

To address this issue, I can think of two ways but both work off this general paradigm:

  1. Store new instance property bool _isInternal
  2. Create private ThreadSafeFunction(napi_threadsafe_function, bool isInternal) to track that it is an internally-created TSFN wrapper. This constructor is used within New
  3. If developer calls existing public ThreadSafeFunction(napi_threadsafe_function), it would default isInternal to false
  4. Use _isInternal inside [Non]BlockingCall and/or CallInternal

Now I say "two" ways because:
1. If we make this _isInternal a const bool on the wrapper, [I believe] we can use static asserts to throw a compile-time error when the with-callback [Non]BlockingCall method is used. However, if it is const, we can no longer use the assignment constructor to overwrite an existing TSFN with a different one, as the property cannot change.
2. Make it non-const, and throw a run-time error.

Edit: option 1 is not feasible

@KevinEady
Copy link
Contributor

As discussed in 21-Oct meeting: The other existing [Non]BlockingCall() methods cover all use-cases for a node-addon-api created TSFN (no data, with function, with function+data). In order to handle this use-case of an already-existing napi_tsfn, we can create new method ThreadSafeFunction::[Non]BlockingCall(DataType* data) which imply to use data with the underlying napi_threadsafe_function directly. Can pass nullptr to use no data.

@KevinEady KevinEady mentioned this issue Oct 22, 2019
15 tasks
mhdawson pushed a commit that referenced this issue Oct 23, 2019
Ref: #556 (comment)
PR-URL: #561
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
KevinEady added a commit to KevinEady/node-addon-api that referenced this issue Oct 29, 2019
KevinEady added a commit to KevinEady/node-addon-api that referenced this issue Oct 29, 2019
mhdawson pushed a commit that referenced this issue Nov 10, 2019
support direct calls to underlying napi_tsfn

Fixes: #556
PR-URL: #58
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
kevindavies8 added a commit to kevindavies8/node-addon-api-Develop that referenced this issue Aug 24, 2022
Ref: nodejs/node-addon-api#556 (comment)
PR-URL: nodejs/node-addon-api#561
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
kevindavies8 added a commit to kevindavies8/node-addon-api-Develop that referenced this issue Aug 24, 2022
support direct calls to underlying napi_tsfn

Fixes: nodejs/node-addon-api#556
PR-URL: nodejs/node-addon-api#58
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
Marlyfleitas added a commit to Marlyfleitas/node-api-addon-Development that referenced this issue Aug 26, 2022
Ref: nodejs/node-addon-api#556 (comment)
PR-URL: nodejs/node-addon-api#561
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Marlyfleitas added a commit to Marlyfleitas/node-api-addon-Development that referenced this issue Aug 26, 2022
support direct calls to underlying napi_tsfn

Fixes: nodejs/node-addon-api#556
PR-URL: nodejs/node-addon-api#58
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
wroy7860 added a commit to wroy7860/addon-api-benchmark-node that referenced this issue Sep 19, 2022
Ref: nodejs/node-addon-api#556 (comment)
PR-URL: nodejs/node-addon-api#561
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
wroy7860 added a commit to wroy7860/addon-api-benchmark-node that referenced this issue Sep 19, 2022
support direct calls to underlying napi_tsfn

Fixes: nodejs/node-addon-api#556
PR-URL: nodejs/node-addon-api#58
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
johnfrench3 pushed a commit to johnfrench3/node-addon-api-git that referenced this issue Aug 11, 2023
Ref: nodejs/node-addon-api#556 (comment)
PR-URL: nodejs/node-addon-api#561
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
johnfrench3 pushed a commit to johnfrench3/node-addon-api-git that referenced this issue Aug 11, 2023
support direct calls to underlying napi_tsfn

Fixes: nodejs/node-addon-api#556
PR-URL: nodejs/node-addon-api#58
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants