X Tutup
The Wayback Machine - https://web.archive.org/web/20220405130637/https://github.com/nodejs/node-addon-api/pull/687
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

tsfn: implement ThreadSafeFunctionEx for GCC 5+ #687

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Copy link
Contributor

@KevinEady KevinEady commented Mar 22, 2020

This PR backs the existing ThreadSafeFunction class with the new ThreadSafeFunctionEx class. However, there are compilation issues on gcc-4.8 used by the CI. node v10 has a minimum build requirement of gcc-4.9.

We discussed somewhere (possibly an N-API meeting) that we can have this PR blocked until node 10 is decommissioned, so we can update our CI's gcc and possibly incorporate these changes.

napi-inl.h Outdated
ContextType* context,
Finalizer finalizeCallback,
FinalizerDataType* data,
napi_threadsafe_function_call_js call_js_cb) {
Copy link
Member

@legendecas legendecas Mar 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it is worth to type the napi_threadsafe_function_call_js with ContextType and DataType.

Copy link
Contributor Author

@KevinEady KevinEady Mar 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@legendecas I was thinking that too, however looking at #594 (comment) , there were complaints that the "wrapping" for CallJS was a performance hit... and I can't think of a way to type napi_threadsafe_function_call_js without making a wrapper.

Furthermore, I don't think DataType can be typed without a wrapper, because it's "declared" in ::New but "used" in ::[Non]BlockingCall, and not sure how to link the two together. The way it works in the existing TSFN is that the napi_threadsafe_function_call_js takes this CallbackWrapper data which is appropriately typed. Without a wrapper, not sure how to accomplish...

@KevinEady
Copy link
Contributor Author

@KevinEady KevinEady commented Mar 24, 2020

Hi @mhdawson / @gabrielschulhof / @legendecas,

In yesterday's meeting we discussed how I removed the multiple overloads for the New method and only kept one that has all parameters. Looking at #544, the last two comments highlight two additional concerns regarding the optional parameter overloads. I believe those are valid, and that's why we I feel we should not have all the possible overloads. This leaves it up to the developer to pass appropriate values. It would also inherently keep up with changing N-API functionality (eg. the new optional Function parameter).

On the contrary, if we did have the multiple overloads, we could N-API version target them via various preprocessor directives, eg. having New with no Function if NAPI > x.

I do think we should just stick with one New method.

Thoughts?

@legendecas
Copy link
Member

@legendecas legendecas commented Mar 26, 2020

@KevinEady I submitted another issue #690 to propose an alternative for the optional Function of New parameter.

So with Maybe boxes, I'd believe we can lean on the one single New.

@KevinEady
Copy link
Contributor Author

@KevinEady KevinEady commented Mar 30, 2020

So @gabrielschulhof / @legendecas / @mhdawson ,

I was working on this over the weekend, and regarding the CallJS wrapper...

To recall, we wanted to wrap it so the New function's call_js_cb

node-addon-api/napi.h

Lines 2045 to 2054 in 90ebd80

static ThreadSafeFunctionEx<ContextType> New(napi_env env,
const Function& callback,
const Object& resource,
ResourceString resourceName,
size_t maxQueueSize,
size_t initialThreadCount,
ContextType* context,
Finalizer finalizeCallback,
FinalizerDataType* data,
napi_threadsafe_function_call_js call_js_cb);

eg. callback

[](napi_env, napi_value, void *context, void *data) { // call_js_cb
std::unique_ptr<CallJsData> callData(static_cast<CallJsData*>(data));
callData->resolve(static_cast<TSFNContext*>(context));
});

would have signature

void(Napi::Env, Napi::Function, ContextType *context, void *data)

However, if we do wrap the callback given to napi_create_threadsafe_function, you would not be able to get the wrapper ThreadSafeFunctionEx<Context>'s underlying napi_threadsafe_function and use it directly with napi_call_threadsafe_function, eg. this behavior would not work:

auto tsfn = Napi::ThreadSafeFunctionEx<Context>::New(env, ....);
napi_call_threadsafe_function(tsfn, ...)

I imagine this is currently an issue in the existing ThreadSafeFunction implementation as well.

FWIW, there was a related problem #556 due to wrapping

@KevinEady
Copy link
Contributor Author

@KevinEady KevinEady commented Apr 7, 2020

Hey @mhdawson / @legendecas / @gabrielschulhof ,

I was able to template the callback parameter as Gabe suggested (woohoo!), and I think the API feels alright... I've included two test cases that show how to use the API:

  1. threadsafe_function_ex/context.cc - showcases a use of ThreadSafeFunctionEx with all templated parameters (context, data type, call js)
  2. threadsafe_function_ex/simple.cc - a very basic tsfn that gives the bare-minimum

I had to add an overload for New that took no finalizer but that is the single overload, as the finalizer data is defaulted to nullptr.

What do you guys think of this implementation?

@KevinEady KevinEady changed the title tsfn: implement ThreadSafeFunctionEx<ContextType> tsfn: implement ThreadSafeFunctionEx Apr 8, 2020
@gabrielschulhof
Copy link
Contributor

@gabrielschulhof gabrielschulhof commented Apr 16, 2020

@KevinEady could you please rebase this so I can try a CI run? As it stands, the CI is affected by #695 and our CI doesn't automatically rebase for testing like core's CI does.

@KevinEady
Copy link
Contributor Author

@KevinEady KevinEady commented Apr 17, 2020

Hi @gabrielschulhof , I've updated with master.

Also, I've added another test to showcase intended api some more -- threadsafe_function_ex/call.cc with no context nor finalizer. /cc @mhdawson @legendecas .

Copy link
Contributor

@gabrielschulhof gabrielschulhof left a comment

The implementation looks good, though AFAICT none of the tests are actually multithreaded. It would be good to have the Napi::ThreadSafeFunctions tests reproduced here to ensure that the class deals correctly with threads.

template <typename ContextType, typename DataType, typename CallJs, CallJs call>
typename std::enable_if<call != nullptr>::type
static inline CallJsWrapper(napi_env env, napi_value jsCallback, void *context, void *data) {
call(env, Function(env, jsCallback), static_cast<ContextType *>(context),
Copy link
Member

@mhdawson mhdawson Apr 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need the if (jsCallback != nullptr) check like the version below or do we expect the CallJs

Copy link
Contributor Author

@KevinEady KevinEady Apr 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @mhdawson ,

Your comment might have got cut off / incomplete but I think I got you...

I do not think we need the jsCallback != nullptr check like below. The call will go into the user-defined CallJs call with an empty function, which I believe is the normal behavior of using the underlying napi tsfn calls with no callback Function but with a CallJs.

@mhdawson
Copy link
Member

@mhdawson mhdawson commented Apr 24, 2020

I assume we need some additions to the docs as well?

@KevinEady
Copy link
Contributor Author

@KevinEady KevinEady commented Apr 26, 2020

The implementation looks good, though AFAICT none of the tests are actually multithreaded. It would be good to have the Napi::ThreadSafeFunctions tests reproduced here to ensure that the class deals correctly with threads.

Hi @gabrielschulhof / @mhdawson / @legendecas

Since the ThreadSafeFunctionEx class can be considered the "base feature" class, I was able to make the existing ThreadSafeFunction class inherit from Ex, thus the existing tests inherently go through Ex. Does this satisfy? Please take a look... None of the public members were changed so I do not think this would affect any backwards compatibility

Well... Going through the different CI errors, messing with templates is not as easy as I imagined.

@KevinEady
Copy link
Contributor Author

@KevinEady KevinEady commented Apr 26, 2020

Hi team,

Going through the errors seen here https://travis-ci.com/github/nodejs/node-addon-api/jobs/323508516#L743 ...

I noticed the node-addon-api CI uses gcc 4.8.4 but the minimum supported gcc version for building node is gcc 6. Aaaand of course, when I test this PR on a gcc 6.1 docker image, it runs fine.

Do we need to support gcc 4? Let's discuss in the next call.

@richardlau
Copy link
Member

@richardlau richardlau commented Apr 27, 2020

Do we need to support gcc 4? Let's discuss in the next call.

If you ever want this to land on 10.x then, yes:
https://github.com/nodejs/node/blob/v10.x/BUILDING.md#unix

@KevinEady KevinEady changed the title tsfn: implement ThreadSafeFunctionEx tsfn: implement ThreadSafeFunctionEx for GCC 5+ Jun 8, 2020
Base automatically changed from master to main Jan 26, 2021
@github-actions github-actions bot added the stale label Dec 21, 2021
@github-actions github-actions bot closed this Jan 20, 2022
@mhdawson mhdawson reopened this Jan 20, 2022
@mhdawson mhdawson removed the stale label Jan 20, 2022
@mhdawson
Copy link
Member

@mhdawson mhdawson commented Jan 21, 2022

We did not discuss in the Node-api team meeting as we ran out of time, but I think since 10.x is officially not supported it can be revisited. See just above https://github.com/nodejs/node-addon-api#setup for where we have documented that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants
X Tutup