n-api: add API for asynchronous functions#17809
n-api: add API for asynchronous functions#17809gabrielschulhof wants to merge 1 commit intonodejs:masterfrom
Conversation
doc/api/n-api.md
Outdated
There was a problem hiding this comment.
hmm.. calling this create_async_function might confuse developers who are using promises since async function() has a very specific meaning in JS
There was a problem hiding this comment.
napi_threadsafe_function?
doc/api/n-api.md
Outdated
There was a problem hiding this comment.
At a glance, there doesn’t appear to be any difference between data and context?
There was a problem hiding this comment.
You're right - I think they pretty much go hand-in-hand.
doc/api/n-api.md
Outdated
There was a problem hiding this comment.
REPLACEME is picked up by tooling automatically :) I think you should also update the NAPI_VERSION #define in node_api.cc?
There was a problem hiding this comment.
Aaaah! Forgot the magic word :)
5e335bb to
945568a
Compare
|
I also removed the context parameter, and updated the YAML tag and the NAPI_VERSION. |
|
Whoops! Forgot to remove the context parameter in the API documentation. |
945568a to
eff8bb3
Compare
|
... and I documented the function pointer types, and updated the version test to expect version 3. |
doc/api/n-api.md
Outdated
There was a problem hiding this comment.
The typedef here and below should be formatted as C code.
doc/api/n-api.md
Outdated
There was a problem hiding this comment.
I'm not sure if these headers should be italicized or not. It's inconsistent throughout the file.
doc/api/n-api.md
Outdated
There was a problem hiding this comment.
Can you line up the function arguments.
src/node_api.cc
Outdated
There was a problem hiding this comment.
The == should be on the previous line I think.
src/node_api.cc
Outdated
There was a problem hiding this comment.
Should async be threadsafe here?
doc/api/n-api.md
Outdated
doc/api/n-api.md
Outdated
There was a problem hiding this comment.
There's no reason it must be that way. Add a mutex and a list or queue, then the uv_async_t becomes like an event-driven condition variable.
There was a problem hiding this comment.
@bnoordhuis @nodejs/addon-api This is indeed value that we could add and this was indeed requested, however, implementing this requires answers to a host of design questions, as the linked comment reveals towards the end.
So, we need to discuss how far beyond exposing libuv and Node functionality we wish to go.
If we decide to implement this queuing, then, in addition to the questions raised by the comment, we need to decide whether to drain the queue using a busy loop or an idle loop, and what limit we should place on the length of the queue. Do we expose both lock and trylock for the mutex so that users might choose whether to block the secondary thread when the queue gets full? How do we dispose of the void* data once the JavaScript function has been called? How close would using such a queue bring this implementation to that of a pipe, and is it worth at that point starting down this path?
TBH, I was going in the opposite direction with this PR (that is, providing less value beyond the essential, rather than more), but I haven't yet had a chance to submit the changes. Instead of a marshal_cb and process_return_cb, I was just going to go with
typedef void (*napi_threadsafe_function_call_js)(napi_env env, napi_value func, void* data);thereby unifying the marshalling and return value processing step. I did that because I realized that we have a lot of if (status != napi_ok) { napi_throw_error(); } and if (status != napi_ok) { napi_fatal_error(); } on the N-API side of the code, and that's perhaps not how the user would want to deal with such failures. Having a single function pointer would push this handling onto the user. Nevertheless, the function pointer would be called from withing a node::CallbackScope so we wouldn't have to remind the user to call the function via napi_make_callback().
I suppose the deeper question is whether we want users using libuv at all. After all, the void* could be a struct { uv_mutex_t mutex; /* useful and thread-safe stuff here; */ }; and then the user would be implementing their own queuing, or any other semantics.
In fact, my only reason for originally splitting the marshalling and return value processing into two steps was to ensure that the actual calling of the JavaScript function was under my control, whereby I could ensure that the call happened via napi_make_callback(). Yet in that incarnation I wasn't using any Node internal APIs, meaning that this whole PR could be implemented externally to Node.
src/node_api.cc
Outdated
src/node_api.cc
Outdated
There was a problem hiding this comment.
VLAs are not 100% portable and prone to blow up the stack when argc is large. You should probably use a std::vector here.
Style: each definition should go on its own line (and separated with ;, not ,.)
src/node_api.cc
Outdated
There was a problem hiding this comment.
There's a C++ equivalent with proper RAII, right? Why don't you use that?
There was a problem hiding this comment.
arraysize(argv)? I realize this is a C file but is there any reason it needs to be?
There was a problem hiding this comment.
That's a node internal, right? We shouldn't be using those in tests.
There was a problem hiding this comment.
&async_data->thread - I've pointed out similar issues several times now and I'll stop doing that from here on. Just stop using this dangerous idiom from now on.
Bundle a uv_async_t and a napi_ref to make it possible to call into JS from another thread. The API accepts a void data and context pointer, an optional native-to-JS function argument marshaller, and a JS-to-native return value marshaller. Fixes: nodejs#13512
eff8bb3 to
65e8f05
Compare
|
Closing this in favour of #17887. |
Bundle a uv_async_t and a napi_ref to make it possible to call into JS from
another thread. The API accepts a void data and context pointer, an optional
native-to-JS function argument marshaller, and a JS-to-native return value
marshaller.
Fixes: #13512
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passesAffected core subsystem(s)
n-api