diff options
Diffstat (limited to 'doc/api/n-api.md')
-rw-r--r-- | doc/api/n-api.md | 374 |
1 files changed, 373 insertions, 1 deletions
diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 5a9c81e369..ff90249606 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -75,7 +75,11 @@ typedef enum { napi_cancelled, napi_escape_called_twice, napi_handle_scope_mismatch, - napi_callback_scope_mismatch + napi_callback_scope_mismatch, +#ifdef NAPI_EXPERIMENTAL + napi_queue_full, + napi_closing, +#endif // NAPI_EXPERIMENTAL } napi_status; ``` If additional information is required upon an API returning a failed status, @@ -113,6 +117,43 @@ not allowed. ### napi_value This is an opaque pointer that is used to represent a JavaScript value. +### napi_threadsafe_function + +> Stability: 1 - Experimental + +This is an opaque pointer that represents a JavaScript function which can be +called asynchronously from multiple threads via +`napi_call_threadsafe_function()`. + +### napi_threadsafe_function_release_mode + +> Stability: 1 - Experimental + +A value to be given to `napi_release_threadsafe_function()` to indicate whether +the thread-safe function is to be closed immediately (`napi_tsfn_abort`) or +merely released (`napi_tsfn_release`) and thus available for subsequent use via +`napi_acquire_threadsafe_function()` and `napi_call_threadsafe_function()`. +```C +typedef enum { + napi_tsfn_release, + napi_tsfn_abort +} napi_threadsafe_function_release_mode; +``` + +### napi_threadsafe_function_call_mode + +> Stability: 1 - Experimental + +A value to be given to `napi_call_threadsafe_function()` to indicate whether +the call should block whenever the queue associated with the thread-safe +function is full. +```C +typedef enum { + napi_tsfn_nonblocking, + napi_tsfn_blocking +} napi_threadsafe_function_call_mode; +``` + ### N-API Memory Management types #### napi_handle_scope This is an abstraction used to control and modify the lifetime of objects @@ -194,6 +235,43 @@ typedef void (*napi_async_complete_callback)(napi_env env, void* data); ``` +#### napi_threadsafe_function_call_js + +> Stability: 1 - Experimental + +Function pointer used with asynchronous thread-safe function calls. The callback +will be called on the main thread. Its purpose is to use a data item arriving +via the queue from one of the secondary threads to construct the parameters +necessary for a call into JavaScript, usually via `napi_call_function`, and then +make the call into JavaScript. + +The data arriving from the secondary thread via the queue is given in the `data` +parameter and the JavaScript function to call is given in the `js_callback` +parameter. + +N-API sets up the environment prior to calling this callback, so it is +sufficient to call the JavaScript function via `napi_call_function` rather than +via `napi_make_callback`. + +Callback functions must satisfy the following signature: +```C +typedef void (*napi_threadsafe_function_call_js)(napi_env env, + napi_value js_callback, + void* context, + void* data); +``` +- `[in] env`: The environment to use for API calls, or `NULL` if the thread-safe +function is being torn down and `data` may need to be freed. +- `[in] js_callback`: The JavaScript function to call, or `NULL` if the +thread-safe function is being torn down and `data` may need to be freed. +- `[in] context`: The optional data with which the thread-safe function was +created. +- `[in] data`: Data created by the secondary thread. It is the responsibility of +the callback to convert this native data to JavaScript values (with N-API +functions) that can be passed as parameters when `js_callback` is invoked. This +pointer is managed entirely by the threads and this callback. Thus this callback +should free the data. + ## Error Handling N-API uses both return values and JavaScript exceptions for error handling. The following sections explain the approach for each case. @@ -3851,6 +3929,298 @@ NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env, - `[in] env`: The environment that the API is invoked under. - `[out] loop`: The current libuv loop instance. +<!-- it's very convenient to have all the anchors indexed --> +<!--lint disable no-unused-definitions remark-lint--> +## Asynchronous Thread-safe Function Calls + +> Stability: 1 - Experimental + +JavaScript functions can normally only be called from a native addon's main +thread. If an addon creates additional threads, then N-API functions that +require a `napi_env`, `napi_value`, or `napi_ref` must not be called from those +threads. + +When an addon has additional threads and JavaScript functions need to be invoked +based on the processing completed by those threads, those threads must +communicate with the addon's main thread so that the main thread can invoke the +JavaScript function on their behalf. The thread-safe function APIs provide an +easy way to do this. + +These APIs provide the type `napi_threadsafe_function` as well as APIs to +create, destroy, and call objects of this type. +`napi_create_threadsafe_function()` creates a persistent reference to a +`napi_value` that holds a JavaScript function which can be called from multiple +threads. The calls happen asynchronously. This means that values with which the +JavaScript callback is to be called will be placed in a queue, and, for each +value in the queue, a call will eventually be made to the JavaScript function. + +Upon creation of a `napi_threadsafe_function` a `napi_finalize` callback can be +provided. This callback will be invoked on the main thread when the thread-safe +function is about to be destroyed. It receives the context and the finalize data +given during construction, and provides an opportunity for cleaning up after the +threads e.g. by calling `uv_thread_join()`. **It is important that, aside from +the main loop thread, there be no threads left using the thread-safe function +after the finalize callback completes.** + +The `context` given during the call to `napi_create_threadsafe_function()` can +be retrieved from any thread with a call to +`napi_get_threadsafe_function_context()`. + +`napi_call_threadsafe_function()` can then be used for initiating a call into +JavaScript. `napi_call_threadsafe_function()` accepts a parameter which controls +whether the API behaves blockingly. If set to `napi_tsfn_nonblocking`, the API +behaves non-blockingly, returning `napi_queue_full` if the queue was full, +preventing data from being successfully added to the queue. If set to +`napi_tsfn_blocking`, the API blocks until space becomes available in the queue. +`napi_call_threadsafe_function()` never blocks if the thread-safe function was +created with a maximum queue size of 0. + +The actual call into JavaScript is controlled by the callback given via the +`call_js_cb` parameter. `call_js_cb` is invoked on the main thread once for each +value that was placed into the queue by a successful call to +`napi_call_threadsafe_function()`. If such a callback is not given, a default +callback will be used, and the resulting JavaScript call will have no arguments. +The `call_js_cb` callback receives the JavaScript function to call as a +`napi_value` in its parameters, as well as the `void*` context pointer used when +creating the `napi_threadsafe_function`, and the next data pointer that was +created by one of the secondary threads. The callback can then use an API such +as `napi_call_function()` to call into JavaScript. + +The callback may also be invoked with `env` and `call_js_cb` both set to `NULL` +to indicate that calls into JavaScript are no longer possible, while items +remain in the queue that may need to be freed. This normally occurs when the +Node.js process exits while there is a thread-safe function still active. + +It is not necessary to call into JavaScript via `napi_make_callback()` because +N-API runs `call_js_cb` in a context appropriate for callbacks. + +Threads can be added to and removed from a `napi_threadsafe_function` object +during its existence. Thus, in addition to specifying an initial number of +threads upon creation, `napi_acquire_threadsafe_function` can be called to +indicate that a new thread will start making use of the thread-safe function. +Similarly, `napi_release_threadsafe_function` can be called to indicate that an +existing thread will stop making use of the thread-safe function. + +`napi_threadsafe_function` objects are destroyed when every thread which uses +the object has called `napi_release_threadsafe_function()` or has received a +return status of `napi_closing` in response to a call to +`napi_call_threadsafe_function`. The queue is emptied before the +`napi_threadsafe_function` is destroyed. It is important that +`napi_release_threadsafe_function()` be the last API call made in conjunction +with a given `napi_threadsafe_function`, because after the call completes, there +is no guarantee that the `napi_threadsafe_function` is still allocated. For the +same reason it is also important that no more use be made of a thread-safe +function after receiving a return value of `napi_closing` in response to a call +to `napi_call_threadsafe_function`. Data associated with the +`napi_threadsafe_function` can be freed in its `napi_finalize` callback which +was passed to `napi_create_threadsafe_function()`. + +Once the number of threads making use of a `napi_threadsafe_function` reaches +zero, no further threads can start making use of it by calling +`napi_acquire_threadsafe_function()`. In fact, all subsequent API calls +associated with it, except `napi_release_threadsafe_function()`, will return an +error value of `napi_closing`. + +The thread-safe function can be "aborted" by giving a value of `napi_tsfn_abort` +to `napi_release_threadsafe_function()`. This will cause all subsequent APIs +associated with the thread-safe function except +`napi_release_threadsafe_function()` to return `napi_closing` even before its +reference count reaches zero. In particular, `napi_call_threadsafe_function()` +will return `napi_closing`, thus informing the threads that it is no longer +possible to make asynchronous calls to the thread-safe function. This can be +used as a criterion for terminating the thread. **Upon receiving a return value +of `napi_closing` from `napi_call_threadsafe_function()` a thread must make no +further use of the thread-safe function because it is no longer guaranteed to +be allocated.** + +Similarly to libuv handles, thread-safe functions can be "referenced" and +"unreferenced". A "referenced" thread-safe function will cause the event loop on +the thread on which it is created to remain alive until the thread-safe function +is destroyed. In contrast, an "unreferenced" thread-safe function will not +prevent the event loop from exiting. The APIs `napi_ref_threadsafe_function` and +`napi_unref_threadsafe_function` exist for this purpose. + +### napi_create_threadsafe_function + +> Stability: 1 - Experimental + +<!-- YAML +added: REPLACEME +--> +```C +NAPI_EXTERN napi_status +napi_create_threadsafe_function(napi_env env, + napi_value func, + napi_value async_resource, + napi_value async_resource_name, + size_t max_queue_size, + size_t initial_thread_count, + void* thread_finalize_data, + napi_finalize thread_finalize_cb, + void* context, + napi_threadsafe_function_call_js call_js_cb, + napi_threadsafe_function* result); +``` + +- `[in] env`: The environment that the API is invoked under. +- `[in] func`: The JavaScript function to call from another thread. +- `[in] async_resource`: An optional object associated with the async work that +will be passed to possible `async_hooks` [`init` hooks][]. +- `[in] async_resource_name`: A javaScript string to provide an identifier for +the kind of resource that is being provided for diagnostic information exposed +by the `async_hooks` API. +- `[in] max_queue_size`: Maximum size of the queue. 0 for no limit. +- `[in] initial_thread_count`: The initial number of threads, including the main +thread, which will be making use of this function. +- `[in] thread_finalize_data`: Data to be passed to `thread_finalize_cb`. +- `[in] thread_finalize_cb`: Function to call when the +`napi_threadsafe_function` is being destroyed. +- `[in] context`: Optional data to attach to the resulting +`napi_threadsafe_function`. +- `[in] call_js_cb`: Optional callback which calls the JavaScript function in +response to a call on a different thread. This callback will be called on the +main thread. If not given, the JavaScript function will be called with no +parameters and with `undefined` as its `this` value. +- `[out] result`: The asynchronous thread-safe JavaScript function. + +### napi_get_threadsafe_function_context + +> Stability: 1 - Experimental + +<!-- YAML +added: REPLACEME +--> +```C +NAPI_EXTERN napi_status +napi_get_threadsafe_function_context(napi_threadsafe_function func, + void** result); +``` + +- `[in] func`: The thread-safe function for which to retrieve the context. +- `[out] context`: The location where to store the context. + +This API may be called from any thread which makes use of `func`. + +### napi_call_threadsafe_function + +> Stability: 1 - Experimental + +<!-- YAML +added: REPLACEME +--> +```C +NAPI_EXTERN napi_status +napi_call_threadsafe_function(napi_threadsafe_function func, + void* data, + napi_threadsafe_function_call_mode is_blocking); +``` + +- `[in] func`: The asynchronous thread-safe JavaScript function to invoke. +- `[in] data`: Data to send into JavaScript via the callback `call_js_cb` +provided during the creation of the thread-safe JavaScript function. +- `[in] is_blocking`: Flag whose value can be either `napi_tsfn_blocking` to +indicate that the call should block if the queue is full or +`napi_tsfn_nonblocking` to indicate that the call should return immediately with +a status of `napi_queue_full` whenever the queue is full. + +This API will return `napi_closing` if `napi_release_threadsafe_function()` was +called with `abort` set to `napi_tsfn_abort` from any thread. The value is only +added to the queue if the API returns `napi_ok`. + +This API may be called from any thread which makes use of `func`. + +### napi_acquire_threadsafe_function + +> Stability: 1 - Experimental + +<!-- YAML +added: REPLACEME +--> +```C +NAPI_EXTERN napi_status +napi_acquire_threadsafe_function(napi_threadsafe_function func); +``` + +- `[in] func`: The asynchronous thread-safe JavaScript function to start making +use of. + +A thread should call this API before passing `func` to any other thread-safe +function APIs to indicate that it will be making use of `func`. This prevents +`func` from being destroyed when all other threads have stopped making use of +it. + +This API may be called from any thread which will start making use of `func`. + +### napi_release_threadsafe_function + +> Stability: 1 - Experimental + +<!-- YAML +added: REPLACEME +--> +```C +NAPI_EXTERN napi_status +napi_release_threadsafe_function(napi_threadsafe_function func, + napi_threadsafe_function_release_mode mode); +``` + +- `[in] func`: The asynchronous thread-safe JavaScript function whose reference +count to decrement. +- `[in] mode`: Flag whose value can be either `napi_tsfn_release` to indicate +that the current thread will make no further calls to the thread-safe function, +or `napi_tsfn_abort` to indicate that in addition to the current thread, no +other thread should make any further calls to the thread-safe function. If set +to `napi_tsfn_abort`, further calls to `napi_call_threadsafe_function()` will +return `napi_closing`, and no further values will be placed in the queue. + +A thread should call this API when it stops making use of `func`. Passing `func` +to any thread-safe APIs after having called this API has undefined results, as +`func` may have been destroyed. + +This API may be called from any thread which will stop making use of `func`. + +### napi_ref_threadsafe_function + +> Stability: 1 - Experimental + +<!-- YAML +added: REPLACEME +--> +```C +NAPI_EXTERN napi_status +napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func); +``` + +- `[in] env`: The environment that the API is invoked under. +- `[in] func`: The thread-safe function to reference. + +This API is used to indicate that the event loop running on the main thread +should not exit until `func` has been destroyed. Similar to [`uv_ref`][] it is +also idempotent. + +This API may only be called from the main thread. + +### napi_unref_threadsafe_function + +> Stability: 1 - Experimental + +<!-- YAML +added: REPLACEME +--> +```C +NAPI_EXTERN napi_status +napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func); +``` + +- `[in] env`: The environment that the API is invoked under. +- `[in] func`: The thread-safe function to unreference. + +This API is used to indicate that the event loop running on the main thread +may exit before `func` is destroyed. Similar to [`uv_unref`][] it is also +idempotent. + +This API may only be called from the main thread. + [ECMAScript Language Specification]: https://tc39.github.io/ecma262/ [Error Handling]: #n_api_error_handling [Native Abstractions for Node.js]: https://github.com/nodejs/nan @@ -3913,6 +4283,8 @@ NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env, [`napi_throw_type_error`]: #n_api_napi_throw_type_error [`napi_unwrap`]: #n_api_napi_unwrap [`napi_wrap`]: #n_api_napi_wrap +[`uv_ref`]: http://docs.libuv.org/en/v1.x/handle.html#c.uv_ref +[`uv_unref`]: http://docs.libuv.org/en/v1.x/handle.html#c.uv_unref [`process.release`]: process.html#process_process_release [`init` hooks]: async_hooks.html#async_hooks_init_asyncid_type_triggerasyncid_resource |