update API

This commit is contained in:
Vladimir Morozov 2024-11-08 07:25:28 -08:00
parent ceaeb11d00
commit 42e76c85b3
16 changed files with 1421 additions and 788 deletions

View File

@ -245,7 +245,7 @@ added: REPLACEME
This is an opaque pointer that represents a Node.js platform configuration
instance.
##### `node_embedding_exit_code`
##### `node_embedding_status`
<!-- YAML
added: REPLACEME
@ -253,53 +253,25 @@ added: REPLACEME
> Stability: 1 - Experimental
The exit code returned from the C Node.js embedding APIs.
The status code returned from the C Node.js embedding APIs.
```c
typedef enum {
node_embedding_exit_code_ok = 0,
node_embedding_exit_code_generic_user_error = 1,
node_embedding_exit_code_internal_js_parse_error = 3,
node_embedding_exit_code_internal_js_evaluation_failure = 4,
node_embedding_exit_code_v8_fatal_error = 5,
node_embedding_exit_code_invalid_fatal_exception_monkey_patching = 6,
node_embedding_exit_code_exception_in_fatal_exception_handler = 7,
node_embedding_exit_code_invalid_command_line_argument = 9,
node_embedding_exit_code_bootstrap_failure = 10,
node_embedding_exit_code_invalid_command_line_argument2 = 12,
node_embedding_exit_code_unsettled_top_level_await = 13,
node_embedding_exit_code_startup_snapshot_failure = 14,
node_embedding_exit_code_abort = 134,
} node_embedding_exit_code;
node_embedding_status_ok = 0,
node_embedding_status_generic_error = 1,
node_embedding_status_null_arg = 2,
node_embedding_status_bad_arg = 3,
node_embedding_status_error_exit_code = 512,
} node_embedding_status;
```
These values match to the C++ `node::ExitCode` enum that are used as Node.js
process exit codes.
- `node_embedding_exit_code_ok` - No issues.
- `node_embedding_exit_code_generic_user_error` - It was originally intended for
uncaught JS exceptions from the user land but we actually use this for all
kinds of generic errors.
- `node_embedding_exit_code_internal_js_parse_error` - It is unused because we
pre-compile all builtins during snapshot building, when we exit with 1 if
there's any error.
- `node_embedding_exit_code_internal_js_evaluation_failure` - It is actually
unused. We exit with 1 in this case.
- `node_embedding_exit_code_v8_fatal_error` - It is actually unused. We exit
with 133 (128+`SIGTRAP`) or 134 (128+`SIGABRT`) in this case.
- `node_embedding_exit_code_invalid_fatal_exception_monkey_patching`
- `node_embedding_exit_code_exception_in_fatal_exception_handler`
- `node_embedding_exit_code_invalid_command_line_argument`
- `node_embedding_exit_code_bootstrap_failure`
- `node_embedding_exit_code_invalid_command_line_argument2` - This was intended
for invalid inspector arguments but is actually now just a duplicate of
`node_embedding_exit_code_invalid_command_line_argument`.
- `node_embedding_exit_code_unsettled_top_level_await` -
- `node_embedding_exit_code_startup_snapshot_failure` -
- `node_embedding_exit_code_abort` - If the process exits from unhandled signals
e.g. `SIGABRT`, `SIGTRAP`, typically the exit codes are 128 + signal number.
We also exit with certain error codes directly for legacy reasons. Here we
define those that are used to normalize the exit code on Windows.
- `node_embedding_status_ok` - No issues.
- `node_embedding_status_generic_error` - Generic error code.
- `node_embedding_status_null_arg` - One of non-optional arguments passed as
NULL value.
- `node_embedding_status_bad_arg` - One of the arguments has wrong value.
- `node_embedding_status_error_exit_code` - A bit flag added to the Node.js exit
code value if the error status is associated with an error code.
##### `node_embedding_platform_flags`
@ -313,53 +285,55 @@ Flags are used to initialize a Node.js platform instance.
```c
typedef enum {
node_embedding_platform_no_flags = 0,
node_embedding_platform_enable_stdio_inheritance = 1 << 0,
node_embedding_platform_disable_node_options_env = 1 << 1,
node_embedding_platform_disable_cli_options = 1 << 2,
node_embedding_platform_no_icu = 1 << 3,
node_embedding_platform_no_stdio_initialization = 1 << 4,
node_embedding_platform_no_default_signal_handling = 1 << 5,
node_embedding_platform_no_init_openssl = 1 << 8,
node_embedding_platform_no_parse_global_debug_variables = 1 << 9,
node_embedding_platform_no_adjust_resource_limits = 1 << 10,
node_embedding_platform_no_use_large_pages = 1 << 11,
node_embedding_platform_no_print_help_or_version_output = 1 << 12,
node_embedding_platform_generate_predictable_snapshot = 1 << 14,
node_embedding_platform_flags_none = 0,
node_embedding_platform_flags_enable_stdio_inheritance = 1 << 0,
node_embedding_platform_flags_disable_node_options_env = 1 << 1,
node_embedding_platform_flags_disable_cli_options = 1 << 2,
node_embedding_platform_flags_no_icu = 1 << 3,
node_embedding_platform_flags_no_stdio_initialization = 1 << 4,
node_embedding_platform_flags_no_default_signal_handling = 1 << 5,
node_embedding_platform_flags_no_init_openssl = 1 << 8,
node_embedding_platform_flags_no_parse_global_debug_variables = 1 << 9,
node_embedding_platform_flags_no_adjust_resource_limits = 1 << 10,
node_embedding_platform_flags_no_use_large_pages = 1 << 11,
node_embedding_platform_flags_no_print_help_or_version_output = 1 << 12,
node_embedding_platform_flags_generate_predictable_snapshot = 1 << 14,
} node_embedding_platform_flags;
```
These flags match to the C++ `node::ProcessInitializationFlags` and control the
Node.js platform initialization.
- `node_embedding_platform_no_flags` - The default flags.
- `node_embedding_platform_enable_stdio_inheritance` - Enable `stdio`
- `node_embedding_platform_flags_none` - The default flags.
- `node_embedding_platform_flags_enable_stdio_inheritance` - Enable `stdio`
inheritance, which is disabled by default. This flag is also implied by the
`node_embedding_platform_no_stdio_initialization`.
- `node_embedding_platform_disable_node_options_env` - Disable reading the
`node_embedding_platform_flags_no_stdio_initialization`.
- `node_embedding_platform_flags_disable_node_options_env` - Disable reading the
`NODE_OPTIONS` environment variable.
- `node_embedding_platform_disable_cli_options` - Do not parse CLI options.
- `node_embedding_platform_no_icu` - Do not initialize ICU.
- `node_embedding_platform_no_stdio_initialization` - Do not modify `stdio` file
descriptor or TTY state.
- `node_embedding_platform_no_default_signal_handling` - Do not register
- `node_embedding_platform_flags_disable_cli_options` - Do not parse CLI
options.
- `node_embedding_platform_flags_no_icu` - Do not initialize ICU.
- `node_embedding_platform_flags_no_stdio_initialization` - Do not modify
`stdio` file descriptor or TTY state.
- `node_embedding_platform_flags_no_default_signal_handling` - Do not register
Node.js-specific signal handlers and reset other signal handlers to
default state.
- `node_embedding_platform_no_init_openssl` - Do not initialize OpenSSL config.
- `node_embedding_platform_no_parse_global_debug_variables` - Do not initialize
Node.js debugging based on environment variables.
- `node_embedding_platform_no_adjust_resource_limits` - Do not adjust OS
- `node_embedding_platform_flags_no_init_openssl` - Do not initialize OpenSSL
config.
- `node_embedding_platform_flags_no_parse_global_debug_variables` - Do not
initialize Node.js debugging based on environment variables.
- `node_embedding_platform_flags_no_adjust_resource_limits` - Do not adjust OS
resource limits for this process.
- `node_embedding_platform_no_use_large_pages` - Do not map code segments into
large pages for this process.
- `node_embedding_platform_no_print_help_or_version_output` - Skip printing
output for `--help`, `--version`, `--v8-options`.
- `node_embedding_platform_generate_predictable_snapshot` - Initialize the
- `node_embedding_platform_flags_no_use_large_pages` - Do not map code segments
into large pages for this process.
- `node_embedding_platform_flags_no_print_help_or_version_output` - Skip
printing output for `--help`, `--version`, `--v8-options`.
- `node_embedding_platform_flags_generate_predictable_snapshot` - Initialize the
process for predictable snapshot generation.
#### Callback types
##### `node_embedding_error_handler`
##### `node_embedding_handle_error_callback`
<!-- YAML
added: REPLACEME
@ -368,11 +342,11 @@ added: REPLACEME
> Stability: 1 - Experimental
```c
typedef node_embedding_exit_code(NAPI_CDECL* node_embedding_error_handler)(
typedef node_embedding_status(NAPI_CDECL* node_embedding_handle_error_callback)(
void* handler_data,
const char* messages[],
size_t messages_size,
node_embedding_exit_code exit_code);
node_embedding_status exit_code);
```
Function pointer type for user-provided native function that handles the list
@ -395,7 +369,7 @@ added: REPLACEME
> Stability: 1 - Experimental
```c
typedef node_embedding_exit_code(
typedef node_embedding_status(
NAPI_CDECL* node_embedding_configure_platform_callback)(
void* cb_data,
node_embedding_platform_config platform_config);
@ -445,7 +419,7 @@ added: REPLACEME
Sets global custom error handler for the Node.js embedded code.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_on_error(node_embedding_error_handler error_handler,
void* error_handler_data);
```
@ -455,7 +429,7 @@ node_embedding_on_error(node_embedding_error_handler error_handler,
passed to the `error_handler` callback. It can be removed after the
`node_embedding_delete_platform()` call.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
It is recommended to call this function before the creation of the
`node_embedding_platform` instance to handle all error messages the same way.
@ -479,7 +453,7 @@ Sets the versions of the C embedding API and the Node-API.
By default the API uses the latest stable versions of the APIs.
```c
node_embedding_exit_code NAPI_CDECL node_embedding_set_api_version(
node_embedding_status NAPI_CDECL node_embedding_set_api_version(
int32_t embedding_api_version,
int32_t node_api_version);
```
@ -487,7 +461,7 @@ node_embedding_exit_code NAPI_CDECL node_embedding_set_api_version(
- `[in] embedding_api_version`: The version of the embedding API.
- `[in] node_api_version`: The version of the Node-API.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
##### `node_embedding_run_main`
@ -502,7 +476,7 @@ It allows to customize the platform, the runtime, and evaluate some Node-API
code after the runtime initialization.
```c
node_embedding_exit_code NAPI_CDECL node_embedding_run_main(
node_embedding_status NAPI_CDECL node_embedding_run_main(
int32_t argc,
char* argv[],
node_embedding_configure_platform_callback configure_platform_cb,
@ -525,7 +499,7 @@ node_embedding_exit_code NAPI_CDECL node_embedding_run_main(
runtime initialization.
- `[in] node_api_cb_data`: Additional data for the `node_api_cb` callback.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
##### `node_embedding_create_platform`
@ -538,7 +512,7 @@ added: REPLACEME
Creates new Node.js platform instance.
```c
node_embedding_exit_code NAPI_CDECL node_embedding_create_platform(
node_embedding_status NAPI_CDECL node_embedding_create_platform(
int32_t argc,
char* argv[],
node_embedding_configure_platform_callback configure_platform_cb,
@ -553,7 +527,7 @@ node_embedding_exit_code NAPI_CDECL node_embedding_create_platform(
`configure_platform_cb` callback.
- `[out] result`: New Node.js platform instance.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
Node.js allows only a single platform instance per process.
@ -568,13 +542,13 @@ added: REPLACEME
Deletes Node.js platform instance.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_delete_platform(node_embedding_platform platform);
```
- `[in] platform`: The Node.js platform instance to delete.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
If the platform was initialized before the deletion, then the method
uninitializes the platform before deletion.
@ -590,7 +564,7 @@ added: REPLACEME
Sets the Node.js platform instance flags.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_platform_set_flags(
node_embedding_platform_config platform_config,
node_embedding_platform_flags flags);
@ -599,7 +573,7 @@ node_embedding_platform_set_flags(
- `[in] platform_config`: The Node.js platform configuration.
- `[in] flags`: The platform flags that control the platform behavior.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
##### `node_embedding_platform_get_parsed_args`
@ -612,7 +586,7 @@ added: REPLACEME
Gets the parsed list of non-Node.js arguments.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_platform_get_parsed_args(
node_embedding_platform platform,
node_embedding_get_args_callback get_args_cb,
@ -630,7 +604,7 @@ node_embedding_platform_get_parsed_args(
to the `get_exec_args_cb` callback. It can be deleted right after the function
call.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
### Runtime instance APIs
@ -744,7 +718,7 @@ added: REPLACEME
> Stability: 1 - Experimental
```c
typedef node_embedding_exit_code(
typedef node_embedding_status(
NAPI_CDECL* node_embedding_configure_runtime_callback)(
void* cb_data,
node_embedding_platform platform,
@ -864,7 +838,7 @@ Runs Node.js runtime environment. It allows to customize the runtime, and
evaluate some Node-API code after the runtime initialization.
```c
NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_run_runtime(
NAPI_EXTERN node_embedding_status NAPI_CDECL node_embedding_run_runtime(
node_embedding_platform platform,
node_embedding_configure_runtime_callback configure_runtime_cb,
void* configure_runtime_cb_data,
@ -880,7 +854,7 @@ NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_run_runtime(
runtime initialization.
- `[in] node_api_cb_data`: Additional data for the `node_api_cb` callback.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
##### `node_embedding_create_runtime`
@ -893,7 +867,7 @@ added: REPLACEME
Creates new Node.js runtime instance.
```c
NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_create_runtime(
NAPI_EXTERN node_embedding_status NAPI_CDECL node_embedding_create_runtime(
node_embedding_platform platform,
node_embedding_configure_runtime_callback configure_runtime_cb,
void* configure_runtime_cb_data,
@ -906,7 +880,7 @@ NAPI_EXTERN node_embedding_exit_code NAPI_CDECL node_embedding_create_runtime(
`configure_runtime_cb` callback.
- `[out] result`: Upon return has a new Node.js runtime instance.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
Creates new Node.js runtime instance based on the provided platform instance.
@ -921,13 +895,13 @@ added: REPLACEME
Deletes Node.js runtime instance.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_delete_runtime(node_embedding_runtime runtime);
```
- `[in] runtime`: The Node.js runtime instance to delete.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
If the runtime was initialized, then the method un-initializes the runtime
before the deletion.
@ -947,7 +921,7 @@ added: REPLACEME
Sets the Node.js runtime instance flags.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_runtime_set_flags(node_embedding_runtime_config runtime_config,
node_embedding_runtime_flags flags);
```
@ -955,14 +929,14 @@ node_embedding_runtime_set_flags(node_embedding_runtime_config runtime_config,
- `[in] runtime_config`: The Node.js runtime configuration.
- `[in] flags`: The runtime flags that control the runtime behavior.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
##### `node_embedding_runtime_set_args`
Sets the non-Node.js arguments for the Node.js runtime instance.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_runtime_set_args(node_embedding_runtime_config runtime_config,
int32_t argc,
const char* argv[],
@ -976,7 +950,7 @@ node_embedding_runtime_set_args(node_embedding_runtime_config runtime_config,
- `[in] exec_argc`: Number of items in the `exec_argv` array.
- `[in] exec_argv`: Node.js arguments as an array of zero terminating strings.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
##### `node_embedding_runtime_on_preload`
@ -989,7 +963,7 @@ added: REPLACEME
Sets a preload callback to call before Node.js runtime instance is loaded.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_runtime_on_preload(
node_embedding_runtime_config runtime_config,
node_embedding_runtime_preload_callback preload_cb,
@ -1003,7 +977,7 @@ node_embedding_runtime_on_preload(
passed to the `preload_cb` callback. It can be removed after the
`node_embedding_delete_runtime` call.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
##### `node_embedding_runtime_on_start_execution`
@ -1017,7 +991,7 @@ Sets a start execution callback to call when Node.js runtime instance
starts execution.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_runtime_on_start_execution(
node_embedding_runtime_config runtime_config,
node_embedding_start_execution_callback start_execution_cb,
@ -1031,7 +1005,7 @@ node_embedding_runtime_on_start_execution(
that will be passed to the `start_execution_cb` callback. It can be removed
after the `node_embedding_delete_runtime` call.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
##### `node_embedding_runtime_add_module`
@ -1044,12 +1018,11 @@ added: REPLACEME
Adds a linked module for the Node.js runtime instance.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_runtime_add_module(
node_embedding_runtime_config runtime_config,
const char* module_name,
node_embedding_initialize_module_callback init_module_cb,
void* init_module_cb_data,
node_embedding_initialize_module_functor init_module,
int32_t module_node_api_version);
```
@ -1060,7 +1033,7 @@ node_embedding_runtime_add_module(
- `[in] init_module_cb_data`: The user data for the init_module_cb.
- `[in] module_node_api_version`: The Node API version used by the module.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
The registered module can be accessed in JavaScript as
`process._linkedBinding(module_name)` in the main JS and in the related
@ -1082,25 +1055,25 @@ The event loop run mode.
```c
typedef enum {
node_embedding_event_loop_run_default = 0,
node_embedding_event_loop_run_once = 1,
node_embedding_event_loop_run_nowait = 2,
node_embedding_event_loop_run_mode_default = 0,
node_embedding_event_loop_run_mode_once = 1,
node_embedding_event_loop_run_mode_nowait = 2,
} node_embedding_event_loop_run_mode;
```
These values match to UV library `uv_run_mode` enum and control the event loop
behavior.
- `node_embedding_event_loop_run_default` - RRun the event loop until it is
- `node_embedding_event_loop_run_mode_default` - RRun the event loop until it is
completed. It matches the `UV_RUN_DEFAULT` behavior.
- `node_embedding_event_loop_run_once` - Run the event loop once and wait if
there are no items. It matches the `UV_RUN_ONCE` behavior.
- `node_embedding_event_loop_run_nowait` - Run the event loop once and do not
wait if there are no items. It matches the `UV_RUN_NOWAIT` behavior.
- `node_embedding_event_loop_run_mode_once` - Run the event loop once and wait
if there are no events. It matches the `UV_RUN_ONCE` behavior.
- `node_embedding_event_loop_run_mode_nowait` - Run the event loop once and do
not wait if there are no events. It matches the `UV_RUN_NOWAIT` behavior.
#### Callback types
##### `node_embedding_event_loop_handler`
##### `node_embedding_post_task_callback`
<!-- YAML
added: REPLACEME
@ -1109,22 +1082,20 @@ added: REPLACEME
> Stability: 1 - Experimental
```c
typedef void(NAPI_CDECL* node_embedding_event_loop_handler)(
node_embedding_runtime runtime,
void* handler_data);
typedef void(NAPI_CDECL* node_embedding_post_task_callback)(
void* cb_data,
node_embedding_run_task_functor run_task);
```
Function pointer type for a handler that is called from the event loop observer
thread when the runtime event loop has some work to do.
Function pointer type for the `node_embedding_post_task_functor` that posts
a task to the task runner.
The callback parameters:
- `[in] runtime`: The runtime owning the callback.
- `[in] handler_data`: The data associated with the callback.
- `[in] cb_data`: The data associated with the callback.
- `[in] run_task`: The task to run in the task runner.
#### Functions
##### `node_embedding_on_wake_up_event_loop`
##### `node_embedding_run_task_callback`
<!-- YAML
added: REPLACEME
@ -1132,29 +1103,105 @@ added: REPLACEME
> Stability: 1 - Experimental
Configures the runtime event loop to use a separate observer thread that calls
the `event_loop_handler` when the runtime event loop has some work to do.
```c
typedef void(NAPI_CDECL* node_embedding_run_task_callback)(
void* cb_data);
```
Function pointer type for the `node_embedding_run_task_functor` that runs
a task by the task runner.
The callback parameters:
- `[in] cb_data`: The data associated with the callback.
#### Functor types
##### `node_embedding_post_task_functor`
<!-- YAML
added: REPLACEME
-->
> Stability: 1 - Experimental
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_on_wake_up_event_loop(
typedef struct {
void* data;
node_embedding_post_task_callback invoke;
node_embedding_release_data_callback release;
} node_embedding_post_task_functor;
```
Functor posts a task to a task runner.
The functor fields:
- `data`: The data associated with the functor.
- `invoke`: The callback with this functor.
- `release`: The callback to delete the `data` associated with this functor.
##### `node_embedding_run_task_functor`
<!-- YAML
added: REPLACEME
-->
> Stability: 1 - Experimental
```c
typedef struct {
void* data;
node_embedding_run_task_callback invoke;
node_embedding_release_data_callback release;
} node_embedding_run_task_functor;
```
Functor that runs a task.
The functor fields:
- `data`: The data associated with the functor.
- `invoke`: The callback with this functor.
- `release`: The callback to delete the `data` associated with this functor.
#### Functions
##### `node_embedding_runtime_set_task_runner`
<!-- YAML
added: REPLACEME
-->
> Stability: 1 - Experimental
Sets the task runner for the Node.js runtime.
It enables running Node.js event loop as a part of application UI event loop or
dispatcher queue.
```c
node_embedding_status NAPI_CDECL
node_embedding_runtime_set_task_runner(
node_embedding_runtime_config runtime_config,
node_embedding_event_loop_handler event_loop_handler,
void* event_loop_handler_data);
node_embedding_post_task_functor post_task);
```
- `[in] runtime_config`: The Node.js runtime configuration.
- `[in] event_loop_handler`: The handler called from the observer thread when
the runtime event loop has some work to do.
- `[in] event_loop_handler_data`: The data associated with the
`event_loop_handler`.
- `[in] post_task`: The functor that is called by the Node.js runtime to run
event loop iteration.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
This function enables running Node.js runtime event loop from the host
application UI event loop. The `event_loop_handler` typically schedules work in
the UI event loop that runs the Node.js event loop. The UI event loop thread and
the observer thread can be stopped until they have something to process.
application UI event loop or a dispatcher queue. Internally it creates a thread
that observes new events to process by the event loop. Then, it posts a task
to run the event loop once using the `post_task` functor.
Note that running the event loop in a dedicated thread is more efficient.
This method can be used in scenarios when we must combine the Node.js event
loop processing with the application UI event loop. It may be required when
the application wants to run JavaScript code from the UI thread to interop with
the native UI components.
##### `node_embedding_run_event_loop`
@ -1167,7 +1214,7 @@ added: REPLACEME
Runs Node.js runtime instance event loop.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_run_event_loop(
node_embedding_runtime runtime,
node_embedding_event_loop_run_mode run_mode,
@ -1178,7 +1225,7 @@ node_embedding_run_event_loop(
- `[in] run_mode`: The mode for running the runtime event loop.
- `[out] has_more_work`: `true` if the event loop has more work to do.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
The function does not complete the Node.js runtime event loop if there are no
more tasks to run.
@ -1192,30 +1239,51 @@ added: REPLACEME
> Stability: 1 - Experimental
Completes the Node.js runtime instance event loop.
It includes completing all current tasks, emitting `beforeExit` event,
completing the new tasks if they added, and emitting `exit` event in the end.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_complete_event_loop(
node_embedding_runtime runtime);
```
- `[in] runtime`: The Node.js runtime instance.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
Note that if new tasks are added in the `beforeExit` event handler, then after
processing these tasks, the `beforeExit` is raised again, and the loop is
continued until the `beforeExit` stops producing new tasks. Only after that the
`exit` event is emitted. No new tasks can be added in the `exit` event handler
or after that.
It completes all current tasks and emits `beforeExit` event.
If new tasks are added, then it completes them and raises the `beforeExit` event
again. The process repeats until the `beforeExit` event stops producing new
tasks. After that it emits the `exit` event and ends the event loop processing.
No new tasks can be added in the `exit` event handler or after that.
##### `node_embedding_terminate_event_loop`
<!-- YAML
added: REPLACEME
-->
> Stability: 1 - Experimental
Terminates the Node.js runtime instance event loop.
```c
node_embedding_status NAPI_CDECL
node_embedding_terminate_event_loop(
node_embedding_runtime runtime);
```
- `[in] runtime`: The Node.js runtime instance.
Returns `node_embedding_status_ok` if there were no issues.
The event loop is stopped and cannot be resumed.
No `beforeExit` or `exit` events are going to be raised.
### JavaScript/Native interop APIs
#### Callback types
##### `node_embedding_node_api_callback`
##### `node_embedding_run_node_api_callback`
<!-- YAML
added: REPLACEME
@ -1224,9 +1292,9 @@ added: REPLACEME
> Stability: 1 - Experimental
```c
typedef void(NAPI_CDECL* node_embedding_node_api_callback)(
node_embedding_runtime runtime
typedef void(NAPI_CDECL* node_embedding_run_node_api_callback)(
void* cb_data,
node_embedding_runtime runtime,
napi_env env);
```
@ -1234,10 +1302,34 @@ Function pointer type for callback that invokes Node-API code.
The callback parameters:
- `[in] runtime`: The Node.js runtime invoking this callback.
- `[in] cb_data`: The user data associated with this callback.
- `[in] runtime`: The Node.js runtime invoking this callback.
- `[in] env`: Node-API environment.
#### Functor types
##### `node_embedding_run_node_api_functor_ref`
<!-- YAML
added: REPLACEME
-->
> Stability: 1 - Experimental
```c
typedef struct {
void* data;
node_embedding_run_node_api_callback invoke;
} node_embedding_run_node_api_functor_ref;
```
Functor reference that invokes Node-API code.
The functor reference fields:
- `data`: The data associated with the functor reference.
- `invoke`: The callback with this functor reference.
#### Functions
##### `node_embedding_run_node_api`
@ -1248,21 +1340,19 @@ added: REPLACEME
> Stability: 1 - Experimental
Invokes a callback that runs Node-API code.
Runs Node-API code.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_run_node_api(
node_embedding_runtime runtime,
node_embedding_node_api_callback node_api_cb,
void* node_api_cb_data);
node_embedding_run_node_api_functor_ref run_node_api);
```
- `[in] runtime`: The Node.js embedding_runtime instance.
- `[in] node_api_cb`: The callback that executes Node-API code.
- `[in] node_api_cb_data`: The data associated with the callback.
- `[in] run_node_api`: The functor reference that invokes Node-API code.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
The function invokes the callback that runs Node-API code in the Node-API scope.
Then, it triggers the uncaught exception handler if there were any
@ -1279,19 +1369,21 @@ added: REPLACEME
Opens scope to run Node-API code.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_open_node_api_scope(
node_embedding_runtime runtime,
node_embedding_node_api_scope* node_api_scope,
napi_env* env);
```
- `[in] runtime`: The Node.js embedding_runtime instance.
- `[out] node_api_scope`: The opened Node-API scope.
- `[out] env`: The Node-API environment that can be used in the scope.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
The function opens up V8 Isolate, V8 handle, and V8 context scopes where it is
safe to the the Node-API environment.
safe to run the Node-API environment.
##### `node_embedding_close_node_api_scope`
@ -1301,17 +1393,19 @@ added: REPLACEME
> Stability: 1 - Experimental
Opens scope to run Node-API code.
Closes the Node-API invocation scope.
```c
node_embedding_exit_code NAPI_CDECL
node_embedding_status NAPI_CDECL
node_embedding_close_node_api_scope(
node_embedding_runtime runtime);
node_embedding_runtime runtime,
node_embedding_node_api_scope node_api_scope);
```
- `[in] runtime`: The Node.js embedding_runtime instance.
- `[in] node_api_scope`: The Node-API scope to close.
Returns `node_embedding_exit_code_ok` if there were no issues.
Returns `node_embedding_status_ok` if there were no issues.
The function closes the V8 Isolate, V8 handle, and V8 context scopes.
Then, it triggers the uncaught exception handler if there were any

View File

@ -1276,13 +1276,15 @@
'sources': [
'src/node_snapshot_stub.cc',
'test/embedding/embedtest.cc',
'test/embedding/embedtest_c_api.cc',
'test/embedding/embedtest_c_api_common.cc',
'test/embedding/embedtest_c_api_common.h',
'test/embedding/embedtest_c_api_env.cc',
'test/embedding/embedtest_c_api_modules.cc',
'test/embedding/embedtest_c_api_preload.cc',
'test/embedding/embedtest_c_api_run_main.cc',
'test/embedding/embedtest_c_api_threading.cc',
'test/embedding/embedtest_main.cc',
'test/embedding/embedtest_modules_node_api.cc',
'test/embedding/embedtest_node_api.cc',
'test/embedding/embedtest_node_api.h',
'test/embedding/embedtest_nodejs_main_node_api.cc',
'test/embedding/embedtest_preload_node_api.cc',
'test/embedding/embedtest_threading_node_api.cc',
],
'conditions': [

View File

@ -88,27 +88,28 @@ struct napi_env__ {
template <typename Call, typename JSExceptionHandler = decltype(HandleThrow)>
inline void CallIntoModule(
Call&& call, JSExceptionHandler&& handle_exception = HandleThrow) {
CallModuleScope scope = OpenCallModuleScope();
CallModuleScopeData scope_data = OpenCallModuleScope();
auto onModuleScopeLeave = node::OnScopeLeave(
[&] { CloseCallModuleScope(scope_data, handle_exception); });
call(this);
CloseCallModuleScope(scope, handle_exception);
}
struct CallModuleScope {
struct CallModuleScopeData {
int open_handle_scopes_before;
int open_callback_scopes_before;
};
inline CallModuleScope OpenCallModuleScope() {
inline CallModuleScopeData OpenCallModuleScope() {
napi_clear_last_error(this);
return {open_handle_scopes, open_callback_scopes};
}
template <typename JSExceptionHandler = decltype(HandleThrow)>
inline void CloseCallModuleScope(
const CallModuleScope& scope,
const CallModuleScopeData& scope_data,
JSExceptionHandler&& handle_exception = HandleThrow) {
CHECK_EQ(open_handle_scopes, scope.open_handle_scopes_before);
CHECK_EQ(open_callback_scopes, scope.open_callback_scopes_before);
CHECK_EQ(open_handle_scopes, scope_data.open_handle_scopes_before);
CHECK_EQ(open_callback_scopes, scope_data.open_callback_scopes_before);
if (!last_exception.IsEmpty()) {
handle_exception(this, last_exception.Get(this->isolate));
last_exception.Reset();

File diff suppressed because it is too large Load Diff

View File

@ -26,11 +26,13 @@ EXTERN_C_START
// Data types
//==============================================================================
typedef struct node_embedding_platform__* node_embedding_platform;
typedef struct node_embedding_runtime__* node_embedding_runtime;
typedef struct node_embedding_platform_config__* node_embedding_platform_config;
typedef struct node_embedding_runtime_config__* node_embedding_runtime_config;
typedef struct node_embedding_platform_s* node_embedding_platform;
typedef struct node_embedding_runtime_s* node_embedding_runtime;
typedef struct node_embedding_platform_config_s* node_embedding_platform_config;
typedef struct node_embedding_runtime_config_s* node_embedding_runtime_config;
typedef struct node_embedding_node_api_scope_s* node_embedding_node_api_scope;
// The status returned by the Node.js embedding API functions.
typedef enum {
node_embedding_status_ok = 0,
node_embedding_status_generic_error = 1,
@ -41,107 +43,113 @@ typedef enum {
node_embedding_status_error_exit_code = 512,
} node_embedding_status;
// The flags for the Node.js platform initialization.
// They match the internal ProcessInitializationFlags::Flags enum.
typedef enum {
node_embedding_platform_no_flags = 0,
node_embedding_platform_flags_none = 0,
// Enable stdio inheritance, which is disabled by default.
// This flag is also implied by
// node_embedding_platform_no_stdio_initialization.
node_embedding_platform_enable_stdio_inheritance = 1 << 0,
// node_embedding_platform_flags_no_stdio_initialization.
node_embedding_platform_flags_enable_stdio_inheritance = 1 << 0,
// Disable reading the NODE_OPTIONS environment variable.
node_embedding_platform_disable_node_options_env = 1 << 1,
node_embedding_platform_flags_disable_node_options_env = 1 << 1,
// Do not parse CLI options.
node_embedding_platform_disable_cli_options = 1 << 2,
node_embedding_platform_flags_disable_cli_options = 1 << 2,
// Do not initialize ICU.
node_embedding_platform_no_icu = 1 << 3,
node_embedding_platform_flags_no_icu = 1 << 3,
// Do not modify stdio file descriptor or TTY state.
node_embedding_platform_no_stdio_initialization = 1 << 4,
node_embedding_platform_flags_no_stdio_initialization = 1 << 4,
// Do not register Node.js-specific signal handlers
// and reset other signal handlers to default state.
node_embedding_platform_no_default_signal_handling = 1 << 5,
node_embedding_platform_flags_no_default_signal_handling = 1 << 5,
// Do not initialize OpenSSL config.
node_embedding_platform_no_init_openssl = 1 << 8,
node_embedding_platform_flags_no_init_openssl = 1 << 8,
// Do not initialize Node.js debugging based on environment variables.
node_embedding_platform_no_parse_global_debug_variables = 1 << 9,
node_embedding_platform_flags_no_parse_global_debug_variables = 1 << 9,
// Do not adjust OS resource limits for this process.
node_embedding_platform_no_adjust_resource_limits = 1 << 10,
node_embedding_platform_flags_no_adjust_resource_limits = 1 << 10,
// Do not map code segments into large pages for this process.
node_embedding_platform_no_use_large_pages = 1 << 11,
node_embedding_platform_flags_no_use_large_pages = 1 << 11,
// Skip printing output for --help, --version, --v8-options.
node_embedding_platform_no_print_help_or_version_output = 1 << 12,
node_embedding_platform_flags_no_print_help_or_version_output = 1 << 12,
// Initialize the process for predictable snapshot generation.
node_embedding_platform_generate_predictable_snapshot = 1 << 14,
node_embedding_platform_flags_generate_predictable_snapshot = 1 << 14,
} node_embedding_platform_flags;
// The flags for the Node.js runtime initialization.
// They match the internal EnvironmentFlags::Flags enum.
typedef enum {
node_embedding_runtime_no_flags = 0,
node_embedding_runtime_flags_none = 0,
// Use the default behavior for Node.js instances.
node_embedding_runtime_default_flags = 1 << 0,
node_embedding_runtime_flags_default = 1 << 0,
// Controls whether this Environment is allowed to affect per-process state
// (e.g. cwd, process title, uid, etc.).
// This is set when using node_embedding_runtime_default_flags.
node_embedding_runtime_owns_process_state = 1 << 1,
// This is set when using node_embedding_runtime_flags_default.
node_embedding_runtime_flags_owns_process_state = 1 << 1,
// Set if this Environment instance is associated with the global inspector
// handling code (i.e. listening on SIGUSR1).
// This is set when using node_embedding_runtime_default_flags.
node_embedding_runtime_owns_inspector = 1 << 2,
// This is set when using node_embedding_runtime_flags_default.
node_embedding_runtime_flags_owns_inspector = 1 << 2,
// Set if Node.js should not run its own esm loader. This is needed by some
// embedders, because it's possible for the Node.js esm loader to conflict
// with another one in an embedder environment, e.g. Blink's in Chromium.
node_embedding_runtime_no_register_esm_loader = 1 << 3,
node_embedding_runtime_flags_no_register_esm_loader = 1 << 3,
// Set this flag to make Node.js track "raw" file descriptors, i.e. managed
// by fs.open() and fs.close(), and close them during
// node_embedding_delete_runtime().
node_embedding_runtime_track_unmanaged_fds = 1 << 4,
node_embedding_runtime_flags_track_unmanaged_fds = 1 << 4,
// Set this flag to force hiding console windows when spawning child
// processes. This is usually used when embedding Node.js in GUI programs on
// Windows.
node_embedding_runtime_hide_console_windows = 1 << 5,
node_embedding_runtime_flags_hide_console_windows = 1 << 5,
// Set this flag to disable loading native addons via `process.dlopen`.
// This environment flag is especially important for worker threads
// so that a worker thread can't load a native addon even if `execArgv`
// is overwritten and `--no-addons` is not specified but was specified
// for this Environment instance.
node_embedding_runtime_no_native_addons = 1 << 6,
node_embedding_runtime_flags_no_native_addons = 1 << 6,
// Set this flag to disable searching modules from global paths like
// $HOME/.node_modules and $NODE_PATH. This is used by standalone apps that
// do not expect to have their behaviors changed because of globally
// installed modules.
node_embedding_runtime_no_global_search_paths = 1 << 7,
node_embedding_runtime_flags_no_global_search_paths = 1 << 7,
// Do not export browser globals like setTimeout, console, etc.
node_embedding_runtime_no_browser_globals = 1 << 8,
node_embedding_runtime_flags_no_browser_globals = 1 << 8,
// Controls whether or not the Environment should call V8Inspector::create().
// This control is needed by embedders who may not want to initialize the V8
// inspector in situations where one has already been created,
// e.g. Blink's in Chromium.
node_embedding_runtime_no_create_inspector = 1 << 9,
node_embedding_runtime_flags_no_create_inspector = 1 << 9,
// Controls whether or not the InspectorAgent for this Environment should
// call StartDebugSignalHandler. This control is needed by embedders who may
// not want to allow other processes to start the V8 inspector.
node_embedding_runtime_no_start_debug_signal_handler = 1 << 10,
node_embedding_runtime_flags_no_start_debug_signal_handler = 1 << 10,
// Controls whether the InspectorAgent created for this Environment waits for
// Inspector frontend events during the Environment creation. It's used to
// call node::Stop(env) on a Worker thread that is waiting for the events.
node_embedding_runtime_no_wait_for_inspector_frontend = 1 << 11
node_embedding_runtime_flags_no_wait_for_inspector_frontend = 1 << 11
} node_embedding_runtime_flags;
typedef enum {
// Run the event loop until it is completed.
// It matches the UV_RUN_DEFAULT behavior.
node_embedding_event_loop_run_default = 0,
node_embedding_event_loop_run_mode_default = 0,
// Run the event loop once and wait if there are no items.
// It matches the UV_RUN_ONCE behavior.
node_embedding_event_loop_run_once = 1,
node_embedding_event_loop_run_mode_once = 1,
// Run the event loop once and do not wait if there are no items.
// It matches the UV_RUN_NOWAIT behavior.
node_embedding_event_loop_run_nowait = 2,
node_embedding_event_loop_run_mode_nowait = 2,
} node_embedding_event_loop_run_mode;
//==============================================================================
// Callbacks
//==============================================================================
typedef node_embedding_status(NAPI_CDECL* node_embedding_error_handler)(
void* handler_data,
typedef void(NAPI_CDECL* node_embedding_release_data_callback)(void* data);
typedef node_embedding_status(NAPI_CDECL* node_embedding_handle_error_callback)(
void* cb_data,
const char* messages[],
size_t messages_size,
node_embedding_status status);
@ -175,6 +183,12 @@ typedef napi_value(NAPI_CDECL* node_embedding_start_execution_callback)(
napi_value require,
napi_value run_cjs);
typedef void(NAPI_CDECL* node_embedding_handle_result_callback)(
void* cb_data,
node_embedding_runtime runtime,
napi_env env,
napi_value value);
typedef napi_value(NAPI_CDECL* node_embedding_initialize_module_callback)(
void* cb_data,
node_embedding_runtime runtime,
@ -182,14 +196,25 @@ typedef napi_value(NAPI_CDECL* node_embedding_initialize_module_callback)(
const char* module_name,
napi_value exports);
typedef void(NAPI_CDECL* node_embedding_event_loop_handler)(
void* handler_data, node_embedding_runtime runtime);
typedef void(NAPI_CDECL* node_embedding_run_task_callback)(void* cb_data);
typedef void(NAPI_CDECL* node_embedding_node_api_callback)(
typedef struct {
void* data;
node_embedding_run_task_callback invoke;
node_embedding_release_data_callback release;
} node_embedding_run_task_functor;
typedef void(NAPI_CDECL* node_embedding_post_task_callback)(
void* cb_data, node_embedding_run_task_functor run_task);
typedef void(NAPI_CDECL* node_embedding_run_node_api_callback)(
void* cb_data, node_embedding_runtime runtime, napi_env env);
typedef void(NAPI_CDECL* node_embedding_release_callback)(
void* data_to_release);
typedef struct {
void* data;
node_embedding_handle_error_callback invoke;
node_embedding_release_data_callback release;
} node_embedding_handle_error_functor;
typedef struct {
void* data;
@ -203,8 +228,8 @@ typedef struct {
typedef struct {
void* data;
node_embedding_node_api_callback invoke;
} node_embedding_node_api_functor_ref;
node_embedding_run_node_api_callback invoke;
} node_embedding_run_node_api_functor_ref;
typedef struct {
void* data;
@ -214,26 +239,32 @@ typedef struct {
typedef struct {
void* data;
node_embedding_preload_callback invoke;
node_embedding_release_callback release;
node_embedding_release_data_callback release;
} node_embedding_preload_functor;
typedef struct {
void* data;
node_embedding_start_execution_callback invoke;
node_embedding_release_callback release;
node_embedding_release_data_callback release;
} node_embedding_start_execution_functor;
typedef struct {
void* data;
node_embedding_handle_result_callback invoke;
node_embedding_release_data_callback release;
} node_embedding_handle_result_functor;
typedef struct {
void* data;
node_embedding_initialize_module_callback invoke;
node_embedding_release_callback release;
node_embedding_release_data_callback release;
} node_embedding_initialize_module_functor;
typedef struct {
void* data;
node_embedding_event_loop_handler invoke;
node_embedding_release_callback release;
} node_embedding_event_loop_functor;
node_embedding_post_task_callback invoke;
node_embedding_release_data_callback release;
} node_embedding_post_task_functor;
//==============================================================================
// Functions
@ -244,8 +275,8 @@ typedef struct {
//------------------------------------------------------------------------------
// Sets the global error handing for the Node.js embedding API.
NAPI_EXTERN node_embedding_status NAPI_CDECL node_embedding_on_error(
node_embedding_error_handler error_handler, void* error_handler_data);
NAPI_EXTERN node_embedding_status NAPI_CDECL
node_embedding_on_error(node_embedding_handle_error_functor error_handler);
//------------------------------------------------------------------------------
// Node.js global platform functions.
@ -260,8 +291,7 @@ NAPI_EXTERN node_embedding_status NAPI_CDECL node_embedding_run_main(
int32_t argc,
char* argv[],
node_embedding_configure_platform_functor_ref configure_platform,
node_embedding_configure_runtime_functor_ref configure_runtime,
node_embedding_node_api_functor_ref run_node_api);
node_embedding_configure_runtime_functor_ref configure_runtime);
// Creates and configures a new Node.js platform instance.
NAPI_EXTERN node_embedding_status NAPI_CDECL node_embedding_create_platform(
@ -284,7 +314,7 @@ NAPI_EXTERN node_embedding_status NAPI_CDECL
node_embedding_platform_get_parsed_args(
node_embedding_platform platform,
node_embedding_get_args_functor_ref get_args,
node_embedding_get_args_functor_ref get_exec_args);
node_embedding_get_args_functor_ref get_runtime_args);
//------------------------------------------------------------------------------
// Node.js runtime functions.
@ -293,8 +323,7 @@ node_embedding_platform_get_parsed_args(
// Runs the Node.js runtime with the provided configuration.
NAPI_EXTERN node_embedding_status NAPI_CDECL node_embedding_run_runtime(
node_embedding_platform platform,
node_embedding_configure_runtime_functor_ref configure_runtime,
node_embedding_node_api_functor_ref run_node_api);
node_embedding_configure_runtime_functor_ref configure_runtime);
// Creates a new Node.js runtime instance.
NAPI_EXTERN node_embedding_status NAPI_CDECL node_embedding_create_runtime(
@ -317,8 +346,8 @@ NAPI_EXTERN node_embedding_status NAPI_CDECL
node_embedding_runtime_set_args(node_embedding_runtime_config runtime_config,
int32_t argc,
const char* argv[],
int32_t exec_argc,
const char* exec_argv[]);
int32_t runtime_argc,
const char* runtime_argv[]);
// Sets the preload callback for the Node.js runtime initialization.
NAPI_EXTERN node_embedding_status NAPI_CDECL
@ -329,7 +358,8 @@ node_embedding_runtime_on_preload(node_embedding_runtime_config runtime_config,
NAPI_EXTERN node_embedding_status NAPI_CDECL
node_embedding_runtime_on_start_execution(
node_embedding_runtime_config runtime_config,
node_embedding_start_execution_functor start_execution);
node_embedding_start_execution_functor start_execution,
node_embedding_handle_result_functor handle_result);
// Adds a new module to the Node.js runtime.
// It is accessed as process._linkedBinding(module_name) in the main JS and in
@ -344,14 +374,15 @@ NAPI_EXTERN node_embedding_status NAPI_CDECL node_embedding_runtime_add_module(
// Node.js runtime functions for the event loop.
//------------------------------------------------------------------------------
// Initializes the runtime to call the provided handler when the runtime event
// loop has some work to do. It starts an observer thread that is stopped by the
// `node_embedding_runtime_complete_event_loop` function call. This function
// helps to integrate the Node.js runtime event loop with the host UI loop.
// Sets the task runner for the Node.js runtime.
// This is an alternative way to run the Node.js runtime event loop that helps
// running it inside of an existing task scheduler.
// E.g. it enables running Node.js event loop inside of the application UI event
// loop or UI dispatcher.
NAPI_EXTERN node_embedding_status NAPI_CDECL
node_embedding_on_wake_up_event_loop(
node_embedding_runtime_set_task_runner(
node_embedding_runtime_config runtime_config,
node_embedding_event_loop_functor run_event_loop);
node_embedding_post_task_functor post_task);
// Runs the Node.js runtime event loop.
NAPI_EXTERN node_embedding_status NAPI_CDECL
@ -364,27 +395,46 @@ node_embedding_run_event_loop(node_embedding_runtime runtime,
NAPI_EXTERN node_embedding_status NAPI_CDECL
node_embedding_complete_event_loop(node_embedding_runtime runtime);
// Stops the Node.js runtime event loop. It cannot be resumed after this call.
NAPI_EXTERN node_embedding_status NAPI_CDECL
node_embedding_terminate_event_loop(node_embedding_runtime runtime);
//------------------------------------------------------------------------------
// Node.js runtime functions for the Node-API interop.
//------------------------------------------------------------------------------
// Runs Node-API code.
NAPI_EXTERN node_embedding_status NAPI_CDECL
node_embedding_run_node_api(node_embedding_runtime runtime,
node_embedding_node_api_functor_ref run_node_api);
// Runs Node-API code in the Node-API scope.
NAPI_EXTERN node_embedding_status NAPI_CDECL node_embedding_run_node_api(
node_embedding_runtime runtime,
node_embedding_run_node_api_functor_ref run_node_api);
// Opens a new Node-API scope.
NAPI_EXTERN node_embedding_status NAPI_CDECL node_embedding_open_node_api_scope(
node_embedding_runtime runtime, napi_env* env);
node_embedding_runtime runtime,
node_embedding_node_api_scope* node_api_scope,
napi_env* env);
// Closes the current Node-API scope.
// Closes the Node-API invocation scope.
NAPI_EXTERN node_embedding_status NAPI_CDECL
node_embedding_close_node_api_scope(node_embedding_runtime runtime);
node_embedding_close_node_api_scope(
node_embedding_runtime runtime,
node_embedding_node_api_scope node_api_scope);
EXTERN_C_END
#ifdef __cplusplus
//==============================================================================
// C++ convenience functions for the C API.
// These functions are not ABI safe and can be changed in future versions.
//==============================================================================
#include <functional>
#include <memory>
#include <type_traits>
namespace node {
//------------------------------------------------------------------------------
// Convenience union operator for the Node.js flags.
//------------------------------------------------------------------------------
@ -401,6 +451,125 @@ inline constexpr node_embedding_runtime_flags operator|(
static_cast<int32_t>(rhs));
}
//------------------------------------------------------------------------------
// Convenience functor struct adapter for C++ function object or lambdas.
//------------------------------------------------------------------------------
namespace details {
template <typename TLambda, typename TFunctor>
struct FunctorAdapter {
static_assert(sizeof(TLambda) == -1, "Unsupported signature");
};
template <typename TLambda, typename TResult, typename... TArgs>
struct FunctorAdapter<TLambda, TResult(void*, TArgs...)> {
static TResult Invoke(void* data, TArgs... args) {
return reinterpret_cast<TLambda*>(data)->operator()(args...);
}
};
template <typename TLambda, typename... TArgs>
struct FunctorAdapter<TLambda, void(void*, TArgs...)> {
static void Invoke(void* data, TArgs... args) {
reinterpret_cast<TLambda*>(data)->operator()(args...);
}
};
template <typename T>
struct FunctorDeleter {
void operator()(T* ptr) {
if (ptr->release != nullptr) {
ptr->release(ptr->data);
}
delete ptr;
}
};
template <typename TFunctor>
struct StdFunctionAdapter {
static_assert(sizeof(TFunctor) == -1, "Unsupported signature");
};
template <typename TResult, typename... TArgs>
struct StdFunctionAdapter<TResult(void*, TArgs...)> {
using FunctionType = std::function<TResult(TArgs...)>;
template <typename TFunctorSharedPtr>
static FunctionType Create(TFunctorSharedPtr&& ptr) {
return ptr ? FunctionType([ptr = std::move(ptr)](TArgs... args) {
return ptr->invoke(ptr->data, args...);
})
: FunctionType(nullptr);
}
};
template <typename... TArgs>
struct StdFunctionAdapter<void(void*, TArgs...)> {
using FunctionType = std::function<void(TArgs...)>;
template <typename TFunctorSharedPtr>
static FunctionType Create(TFunctorSharedPtr&& ptr) {
return ptr ? FunctionType([ptr = std::move(ptr)](TArgs... args) {
ptr->invoke(ptr->data, args...);
})
: FunctionType(nullptr);
}
};
} // namespace details
template <typename TFunctor, typename TLambda>
inline TFunctor AsFunctorRef(TLambda&& lambda) {
using TLambdaType = std::remove_reference_t<TLambda>;
using TAdapter = details::FunctorAdapter<
TLambdaType,
std::remove_pointer_t<
decltype(std::remove_reference_t<TFunctor>::invoke)>>;
return TFunctor{static_cast<void*>(&lambda), &TAdapter::Invoke};
}
template <typename TFunctor, typename TLambda>
inline TFunctor AsFunctor(TLambda&& lambda) {
using TLambdaType = std::remove_reference_t<TLambda>;
using TAdapter = details::FunctorAdapter<
TLambdaType,
std::remove_pointer_t<
decltype(std::remove_reference_t<TFunctor>::invoke)>>;
return TFunctor{
static_cast<void*>(new TLambdaType(std::forward<TLambdaType>(lambda))),
&TAdapter::Invoke,
[](void* data) { delete static_cast<TLambdaType*>(data); }};
}
template <typename T>
using FunctorPtr = std::unique_ptr<T, details::FunctorDeleter<T>>;
template <typename T>
FunctorPtr<T> MakeUniqueFunctorPtr(const T& functor) {
return functor.invoke ? FunctorPtr<T>(new T(functor)) : nullptr;
}
template <typename T>
std::shared_ptr<T> MakeSharedFunctorPtr(const T& functor) {
return functor.invoke
? std::shared_ptr<T>(new T(functor), details::FunctorDeleter<T>())
: nullptr;
}
template <typename TFunctor>
using StdFunction = typename details::StdFunctionAdapter<std::remove_pointer_t<
decltype(std::remove_reference_t<TFunctor>::invoke)>>::FunctionType;
template <typename TFunctor>
inline StdFunction<TFunctor> AsStdFunction(TFunctor&& functor) {
using TAdapter = details::StdFunctionAdapter<std::remove_pointer_t<
decltype(std::remove_reference_t<TFunctor>::invoke)>>;
return TAdapter::Create(std::move(MakeSharedFunctorPtr(functor)));
}
} // namespace node
#endif
#endif // SRC_NODE_EMBEDDING_API_H_

View File

@ -1,7 +1,7 @@
# C embedding API
This file is an overview for C embedding API.
It is mostly to catch all the work in progress notes.
It is mostly to catch all the work in progress.
## The API overview
@ -40,32 +40,85 @@ It is mostly to catch all the work in progress notes.
- `node_embedding_open_node_api_scope`
- `node_embedding_close_node_api_scope`
### API TODOs
## Functional overview
### Platform API
- Global handling of C API errors
- [ ] Global handling of Node.js/V8 errors (is it possible?)
- [ ] Global handling of unhandled JS errors
- API version
- Node-API version
- Global platform initialization
- Global platform uninitialization
- Parsing the command line parameters
- Controlled by the platform flags
- Get parsed command line arguments
- [ ] Allow running Node.js uv_loop from UI loop. Follow the Electron
implementation. - Complete implementation for non-Windows.
- [ ] Can we use some kind of waiter concept instead of the
observer thread?
- [ ] Generate the main script based on the runtime settings.
- [ ] Set the global Inspector for he main runtime.
- [ ] Start workers from C++.
- [ ] Worker to inherit parent Inspector.
- [ ] Cancel pending event loop tasks on runtime deletion.
- [ ] Can we initialize platform again if it returns early?
- [ ] Test passing the V8 thread pool size.
- [ ] Add a way to terminate the runtime.
- [ ] Allow to provide custom thread pool from the app.
- [ ] Consider adding a v-table for the API functions to simplify
binding with other languages.
- [ ] We must not exit the process on node::Environment errors.
- [ ] Be explicit about the recoverable errors.
- [ ] Store IsolateScope in TLS.
- [-] Will not support: custom thread pool
- [ ] API v-table to avoid DLL named function binding
### Runtime API
- Runtime initialization
- Runtime uninitialization
- Set runtime args
- Set runtime flags
- Register a preload callback
- Register start execution callback
- [ ] Load default Node.js snapshot without the custom start execution callback
- [ ] Get the returned value from the start execution
- Register linked modules
- [ ] Runtime handling of API errors (is it possible?)
- [ ] Runtime handling of Node.js/V8 errors (is it possible?)
- [ ] Runtime handling of unhandled JS errors
- [ ] Events on Runtime destruction (beforeExit, exit)
- [ ] Main vs secondary Runtimes
- [ ] Worker thread runtimes (is it possible?)
- [ ] Associate Inspector with the Runtime
- [ ] Inspector for the secondary Runtimes
- [ ] Runtime destructor to clean up all related resources including the
pending tasks.
- [ ] Exit process only for unhandled main runtime errors.
- [ ] Have an internal list of all runtimes in the system.
It is a list of all secondary runtimes attached to the main runtime.
### Event Loop API
- Run event loop while it has events (default)
- Run event loop once and block for an event
- Run event loop once and no wait
- Run event loop till completion
- [ ] Interrupt the event loop (uv_stop stops the default loop and then
the loop resets it)
- [ ] Loop while some condition is true
- [ ] Custom foreground task runner (is it possible?)
- [ ] Notify if event loop has work to do (based on Electron PollEvents)
It must be blocked while the loop is running
It is only for the main runtime
- [ ] V8 Microtask posting and draining
- [ ] Complete the loop immediately if needed
- [ ] Protect from nested uv_run calls
- [ ] How to post setImmediate from another thread?
### Node-API integration
- Run Node-API code as a lambda
- Explicitly open and close the Node-API scope
- [ ] Handle JS errors
### Test TODOs
- [ ] Test passing the V8 thread pool size.
- [ ] Add tests based on the environment and platform `cctest`s.
- [ ] Enable the test_main_modules_node_api test.
- [ ] Test failure in Preload callback.
- [ ] Test failure in linked modules.
- [ ] Add a test that handles JS errors.
- [ ] Make sure that the delete calls match the create calls.
- [ ] Make sure that the the delete calls match the create calls.

View File

@ -1,21 +1,18 @@
#include "embedtest_node_api.h"
#include "embedtest_c_api_common.h"
#include <cassert>
#include <cstdarg>
#include <cstdio>
#include <cstring>
const char* main_script =
"globalThis.require = require('module').createRequire(process.execPath);\n"
"globalThis.embedVars = { nön_ascıı: '🏳️‍🌈' };\n"
"require('vm').runInThisContext(process.argv[1]);";
using namespace node;
void CallMe(node_embedding_runtime runtime, napi_env env);
void WaitMe(node_embedding_runtime runtime, napi_env env);
void WaitMeWithCheese(node_embedding_runtime runtime, napi_env env);
extern "C" int32_t test_main_node_api(int32_t argc, char* argv[]) {
node_embedding_on_error(HandleTestError, argv[0]);
node_embedding_on_error({argv[0], HandleTestError, nullptr});
CHECK_STATUS_OR_EXIT(node_embedding_run_main(
argc,
@ -24,92 +21,29 @@ extern "C" int32_t test_main_node_api(int32_t argc, char* argv[]) {
[&](node_embedding_platform_config platform_config) {
CHECK_STATUS(node_embedding_platform_set_flags(
platform_config,
node_embedding_platform_disable_node_options_env));
node_embedding_platform_flags_disable_node_options_env));
return node_embedding_status_ok;
}),
AsFunctorRef<node_embedding_configure_runtime_functor_ref>(
[&](node_embedding_platform platform,
node_embedding_runtime_config runtime_config) {
CHECK_STATUS(node_embedding_runtime_on_start_execution(
runtime_config,
AsFunctor<node_embedding_start_execution_functor>(
[](node_embedding_runtime runtime,
napi_env env,
napi_value process,
napi_value require,
napi_value run_cjs) -> napi_value {
napi_status status{};
napi_value script, undefined, result;
NODE_API_CALL(napi_create_string_utf8(
env, main_script, NAPI_AUTO_LENGTH, &script));
NODE_API_CALL(napi_get_undefined(env, &undefined));
NODE_API_CALL(napi_call_function(
env, undefined, run_cjs, 1, &script, &result));
return result;
})));
CHECK_STATUS(
LoadUtf8Script(runtime_config,
main_script,
AsFunctor<node_embedding_handle_result_functor>(
[&](node_embedding_runtime runtime,
napi_env env,
napi_value /*value*/) {
CallMe(runtime, env);
WaitMe(runtime, env);
WaitMeWithCheese(runtime, env);
})));
return node_embedding_status_ok;
}),
AsFunctorRef<node_embedding_node_api_functor_ref>(
[&](node_embedding_runtime runtime, napi_env env) {
CallMe(runtime, env);
WaitMe(runtime, env);
WaitMeWithCheese(runtime, env);
})));
return node_embedding_status_ok;
}
napi_status AddUtf8String(std::string& str, napi_env env, napi_value value) {
size_t str_size = 0;
napi_status status =
napi_get_value_string_utf8(env, value, nullptr, 0, &str_size);
if (status != napi_ok) {
return status;
}
size_t offset = str.size();
str.resize(offset + str_size);
status = napi_get_value_string_utf8(
env, value, &str[0] + offset, str_size + 1, &str_size);
return status;
}
void GetAndThrowLastErrorMessage(napi_env env) {
const napi_extended_error_info* error_info;
napi_get_last_error_info(env, &error_info);
bool is_pending;
const char* err_message = error_info->error_message;
napi_is_exception_pending((env), &is_pending);
/* If an exception is already pending, don't rethrow it */
if (!is_pending) {
const char* error_message =
err_message != nullptr ? err_message : "empty error message";
napi_throw_error((env), nullptr, error_message);
}
}
void ThrowLastErrorMessage(napi_env env, const char* message) {
bool is_pending;
napi_is_exception_pending(env, &is_pending);
/* If an exception is already pending, don't rethrow it */
if (!is_pending) {
const char* error_message =
message != nullptr ? message : "empty error message";
napi_throw_error(env, nullptr, error_message);
}
}
std::string FormatString(const char* format, ...) {
va_list args1;
va_start(args1, format);
va_list args2;
va_copy(args2, args1); // Required for some compilers like GCC.
std::string result(std::vsnprintf(nullptr, 0, format, args1), '\0');
va_end(args1);
std::vsnprintf(&result[0], result.size() + 1, format, args2);
va_end(args2);
return result;
}
void CallMe(node_embedding_runtime runtime, napi_env env) {
napi_value global;
napi_value cb;
@ -190,7 +124,7 @@ void WaitMe(node_embedding_runtime runtime, napi_env env) {
}
node_embedding_run_event_loop(
runtime, node_embedding_event_loop_run_default, nullptr);
runtime, node_embedding_event_loop_run_mode_default, nullptr);
if (strcmp(callback_buf, "waited you") != 0) {
NODE_API_FAIL_RETURN_VOID("Invalid value received: %s\n", callback_buf);
@ -291,7 +225,7 @@ void WaitMeWithCheese(node_embedding_runtime runtime, napi_env env) {
while (promise_state == PromiseState::kPending) {
node_embedding_run_event_loop(
runtime, node_embedding_event_loop_run_nowait, nullptr);
runtime, node_embedding_event_loop_run_mode_nowait, nullptr);
}
expected = (promise_state == PromiseState::kFulfilled)

View File

@ -0,0 +1,87 @@
#include "embedtest_c_api_common.h"
#include <cassert>
#include <cstdarg>
#include <cstdio>
#include <cstring>
using namespace node;
const char* main_script =
"globalThis.require = require('module').createRequire(process.execPath);\n"
"globalThis.embedVars = { nön_ascıı: '🏳️‍🌈' };\n"
"require('vm').runInThisContext(process.argv[1]);";
napi_status AddUtf8String(std::string& str, napi_env env, napi_value value) {
size_t str_size = 0;
napi_status status =
napi_get_value_string_utf8(env, value, nullptr, 0, &str_size);
if (status != napi_ok) {
return status;
}
size_t offset = str.size();
str.resize(offset + str_size);
status = napi_get_value_string_utf8(
env, value, &str[0] + offset, str_size + 1, &str_size);
return status;
}
void GetAndThrowLastErrorMessage(napi_env env) {
const napi_extended_error_info* error_info;
napi_get_last_error_info(env, &error_info);
bool is_pending;
const char* err_message = error_info->error_message;
napi_is_exception_pending((env), &is_pending);
/* If an exception is already pending, don't rethrow it */
if (!is_pending) {
const char* error_message =
err_message != nullptr ? err_message : "empty error message";
napi_throw_error((env), nullptr, error_message);
}
}
void ThrowLastErrorMessage(napi_env env, const char* message) {
bool is_pending;
napi_is_exception_pending(env, &is_pending);
/* If an exception is already pending, don't rethrow it */
if (!is_pending) {
const char* error_message =
message != nullptr ? message : "empty error message";
napi_throw_error(env, nullptr, error_message);
}
}
std::string FormatString(const char* format, ...) {
va_list args1;
va_start(args1, format);
va_list args2;
va_copy(args2, args1); // Required for some compilers like GCC.
std::string result(std::vsnprintf(nullptr, 0, format, args1), '\0');
va_end(args1);
std::vsnprintf(&result[0], result.size() + 1, format, args2);
va_end(args2);
return result;
}
node_embedding_status LoadUtf8Script(
node_embedding_runtime_config runtime_config,
std::string script,
const node_embedding_handle_result_functor& handle_result) {
return node_embedding_runtime_on_start_execution(
runtime_config,
AsFunctor<node_embedding_start_execution_functor>(
[script = std::move(script)](node_embedding_runtime /*runtime*/,
napi_env env,
napi_value /*process*/,
napi_value /*require*/,
napi_value run_cjs) -> napi_value {
napi_value script_value, null_value, result;
NODE_API_CALL(napi_create_string_utf8(
env, script.c_str(), script.size(), &script_value));
NODE_API_CALL(napi_get_null(env, &null_value));
NODE_API_CALL(napi_call_function(
env, null_value, run_cjs, 1, &script_value, &result));
return result;
}),
handle_result);
}

View File

@ -10,11 +10,37 @@
#include <string>
#include <vector>
extern "C" inline void NAPI_CDECL GetArgsVector(void* data,
int32_t argc,
const char* argv[]) {
static_cast<std::vector<std::string>*>(data)->assign(argv, argv + argc);
}
template <size_t kInplaceBufferSize = 32>
class CStringArray {
public:
explicit CStringArray(const std::vector<std::string>& strings) noexcept
: size_(strings.size()) {
if (size_ <= inplace_buffer_.size()) {
c_strs_ = inplace_buffer_.data();
} else {
allocated_buffer_ = std::make_unique<const char*[]>(size_);
c_strs_ = allocated_buffer_.get();
}
for (size_t i = 0; i < size_; ++i) {
c_strs_[i] = strings[i].c_str();
}
}
CStringArray(const CStringArray&) = delete;
CStringArray& operator=(const CStringArray&) = delete;
const char** c_strs() const { return c_strs_; }
size_t size() const { return size_; }
const char** argv() const { return c_strs_; }
int32_t argc() const { return static_cast<int32_t>(size_); }
private:
const char** c_strs_{};
size_t size_{};
std::array<const char*, kInplaceBufferSize> inplace_buffer_;
std::unique_ptr<const char*[]> allocated_buffer_;
};
extern "C" inline node_embedding_status NAPI_CDECL
HandleTestError(void* handler_data,
@ -38,7 +64,7 @@ HandleTestError(void* handler_data,
return node_embedding_status_ok;
}
#endif
#endif // __cplusplus
extern const char* main_script;
@ -50,40 +76,10 @@ void ThrowLastErrorMessage(napi_env env, const char* message);
std::string FormatString(const char* format, ...);
template <typename TLambda, typename TFunctor>
struct Adapter {
static_assert(sizeof(TLambda) == -1, "Unsupported signature");
};
template <typename TLambda, typename TResult, typename... TArgs>
struct Adapter<TLambda, TResult(void*, TArgs...)> {
static TResult Invoke(void* data, TArgs... args) {
return reinterpret_cast<TLambda*>(data)->operator()(args...);
}
};
template <typename TFunctor, typename TLambda>
inline TFunctor AsFunctorRef(TLambda&& lambda) {
using TLambdaType = std::remove_reference_t<TLambda>;
using TAdapter =
Adapter<TLambdaType,
std::remove_pointer_t<
decltype(std::remove_reference_t<TFunctor>::invoke)>>;
return TFunctor{static_cast<void*>(&lambda), &TAdapter::Invoke};
}
template <typename TFunctor, typename TLambda>
inline TFunctor AsFunctor(TLambda&& lambda) {
using TLambdaType = std::remove_reference_t<TLambda>;
using TAdapter =
Adapter<TLambdaType,
std::remove_pointer_t<
decltype(std::remove_reference_t<TFunctor>::invoke)>>;
return TFunctor{
static_cast<void*>(new TLambdaType(std::forward<TLambdaType>(lambda))),
&TAdapter::Invoke,
[](void* data) { delete static_cast<TLambdaType*>(data); }};
}
node_embedding_status LoadUtf8Script(
node_embedding_runtime_config runtime_config,
std::string script,
const node_embedding_handle_result_functor& handle_result = {});
//
// Error handling macros copied from test/js_native_api/common.h

View File

@ -0,0 +1,113 @@
#include "embedtest_c_api_common.h"
using namespace node;
// Test the no_browser_globals option.
extern "C" int32_t test_main_c_api_env_no_browser_globals(int32_t argc,
char* argv[]) {
return node_embedding_run_main(
argc,
argv,
{},
AsFunctorRef<node_embedding_configure_runtime_functor_ref>(
[](node_embedding_platform platform,
node_embedding_runtime_config runtime_config) {
CHECK_STATUS(node_embedding_runtime_set_flags(
runtime_config,
node_embedding_runtime_flags_no_browser_globals));
return LoadUtf8Script(runtime_config,
R"JS(
const assert = require('assert');
const path = require('path');
const relativeRequire =
require('module').createRequire(path.join(process.cwd(), 'stub.js'));
const { intrinsics, nodeGlobals } =
relativeRequire('./test/common/globals');
const items = Object.getOwnPropertyNames(globalThis);
const leaks = [];
for (const item of items) {
if (intrinsics.has(item)) {
continue;
}
if (nodeGlobals.has(item)) {
continue;
}
if (item === '$jsDebugIsRegistered') {
continue;
}
leaks.push(item);
}
assert.deepStrictEqual(leaks, []);
)JS");
}));
}
// Test ESM loaded
extern "C" int32_t test_main_c_api_env_with_esm_loader(int32_t argc,
char* argv[]) {
// We currently cannot pass argument to command line arguments to the runtime.
// They must be parsed by the platform.
std::vector<std::string> args_vec(argv, argv + argc);
args_vec.push_back("--experimental-vm-modules");
CStringArray args(args_vec);
return node_embedding_run_main(
args.argc(),
const_cast<char**>(args.argv()),
{},
AsFunctorRef<node_embedding_configure_runtime_functor_ref>(
[](node_embedding_platform platform,
node_embedding_runtime_config runtime_config) {
return LoadUtf8Script(runtime_config,
R"JS(
globalThis.require = require('module').createRequire(process.execPath);
const { SourceTextModule } = require('node:vm');
(async () => {
const stmString = 'globalThis.importResult = import("")';
const m = new SourceTextModule(stmString, {
importModuleDynamically: (async () => {
const m = new SourceTextModule('');
await m.link(() => 0);
await m.evaluate();
return m.namespace;
}),
});
await m.link(() => 0);
await m.evaluate();
delete globalThis.importResult;
process.exit(0);
})();
)JS");
}));
}
// Test ESM loaded
extern "C" int32_t test_main_c_api_env_with_no_esm_loader(int32_t argc,
char* argv[]) {
return node_embedding_run_main(
argc,
argv,
{},
AsFunctorRef<node_embedding_configure_runtime_functor_ref>(
[](node_embedding_platform platform,
node_embedding_runtime_config runtime_config) {
return LoadUtf8Script(runtime_config,
R"JS(
globalThis.require = require('module').createRequire(process.execPath);
const { SourceTextModule } = require('node:vm');
(async () => {
const stmString = 'globalThis.importResult = import("")';
const m = new SourceTextModule(stmString, {
importModuleDynamically: (async () => {
const m = new SourceTextModule('');
await m.link(() => 0);
await m.evaluate();
return m.namespace;
}),
});
await m.link(() => 0);
await m.evaluate();
delete globalThis.importResult;
})();
)JS");
}));
}

View File

@ -1,9 +1,11 @@
#include "embedtest_node_api.h"
#include "embedtest_c_api_common.h"
#include <atomic>
#include <cstdio>
#include <cstring>
using namespace node;
class GreeterModule {
public:
explicit GreeterModule(std::atomic<int32_t>* counter_ptr)
@ -89,7 +91,7 @@ extern "C" int32_t test_main_linked_modules_node_api(int32_t argc,
std::atomic<int32_t> greeterModuleInitCallCount{0};
std::atomic<int32_t> replicatorModuleInitCallCount{0};
node_embedding_on_error(HandleTestError, argv[0]);
node_embedding_on_error({argv[0], HandleTestError, nullptr});
CHECK_STATUS_OR_EXIT(node_embedding_run_main(
argc,
@ -124,25 +126,10 @@ extern "C" int32_t test_main_linked_modules_node_api(int32_t argc,
ReplicatorModule(&replicatorModuleInitCallCount)),
NAPI_VERSION));
CHECK_STATUS(node_embedding_runtime_on_start_execution(
runtime_config,
AsFunctor<node_embedding_start_execution_functor>(
[](node_embedding_runtime runtime,
napi_env env,
napi_value process,
napi_value require,
napi_value run_cjs) -> napi_value {
napi_value script, undefined, result;
NODE_API_CALL(napi_create_string_utf8(
env, main_script, NAPI_AUTO_LENGTH, &script));
NODE_API_CALL(napi_get_undefined(env, &undefined));
NODE_API_CALL(napi_call_function(
env, undefined, run_cjs, 1, &script, &result));
return result;
})));
CHECK_STATUS(LoadUtf8Script(runtime_config, main_script));
return node_embedding_status_ok;
}),
{}));
})));
ASSERT_OR_EXIT(greeterModuleInitCallCount ==
expectedGreeterModuleInitCallCount);

View File

@ -1,8 +1,10 @@
#include "embedtest_node_api.h"
#include "embedtest_c_api_common.h"
#include <mutex>
#include <thread>
using namespace node;
// Tests that the same preload callback is called from the main thread and from
// the worker thread.
extern "C" int32_t test_main_preload_node_api(int32_t argc, char* argv[]) {
@ -28,26 +30,11 @@ extern "C" int32_t test_main_preload_node_api(int32_t argc, char* argv[]) {
NODE_API_CALL_RETURN_VOID(napi_set_named_property(
env, global, "preloadValue", value));
})));
CHECK_STATUS(node_embedding_runtime_on_start_execution(
runtime_config,
AsFunctor<node_embedding_start_execution_functor>(
[](node_embedding_runtime runtime,
napi_env env,
napi_value process,
napi_value require,
napi_value run_cjs) -> napi_value {
napi_value script, undefined, result;
NODE_API_CALL(napi_create_string_utf8(
env, main_script, NAPI_AUTO_LENGTH, &script));
NODE_API_CALL(napi_get_undefined(env, &undefined));
NODE_API_CALL(napi_call_function(
env, undefined, run_cjs, 1, &script, &result));
return result;
})));
CHECK_STATUS(LoadUtf8Script(runtime_config, main_script));
return node_embedding_status_ok;
}),
{}));
})));
return 0;
}

View File

@ -4,5 +4,5 @@
// invoked from the libnode shared library as it would be run from the Node.js
// CLI. No embedder customizations are available in this case.
extern "C" int32_t test_main_nodejs_main_node_api(int32_t argc, char* argv[]) {
return node_embedding_run_main(argc, argv, {}, {}, {});
return node_embedding_run_main(argc, argv, {}, {});
}

View File

@ -1,10 +1,12 @@
#include "embedtest_node_api.h"
#include "embedtest_c_api_common.h"
#include <condition_variable>
#include <deque>
#include <mutex>
#include <thread>
using namespace node;
// Tests that multiple runtimes can be run at the same time in their own
// threads. The test creates 12 threads and 12 runtimes. Each runtime runs in it
// own thread.
@ -35,36 +37,26 @@ extern "C" int32_t test_main_threading_runtime_per_thread_node_api(
// process.
CHECK_STATUS(node_embedding_runtime_set_flags(
runtime_config,
node_embedding_runtime_default_flags |
node_embedding_runtime_no_create_inspector));
CHECK_STATUS(node_embedding_runtime_on_start_execution(
node_embedding_runtime_flags_default |
node_embedding_runtime_flags_no_create_inspector));
CHECK_STATUS(LoadUtf8Script(
runtime_config,
AsFunctor<node_embedding_start_execution_functor>(
[](node_embedding_runtime runtime,
napi_env env,
napi_value process,
napi_value require,
napi_value run_cjs) -> napi_value {
napi_value script, undefined, result;
NODE_API_CALL(napi_create_string_utf8(
env, main_script, NAPI_AUTO_LENGTH, &script));
NODE_API_CALL(napi_get_undefined(env, &undefined));
NODE_API_CALL(napi_call_function(
env, undefined, run_cjs, 1, &script, &result));
return result;
main_script,
AsFunctor<node_embedding_handle_result_functor>(
[&](node_embedding_runtime runtime,
napi_env env,
napi_value /*value*/) {
napi_value global, my_count;
NODE_API_CALL_RETURN_VOID(
napi_get_global(env, &global));
NODE_API_CALL_RETURN_VOID(napi_get_named_property(
env, global, "myCount", &my_count));
int32_t count;
NODE_API_CALL_RETURN_VOID(
napi_get_value_int32(env, my_count, &count));
global_count.fetch_add(count);
})));
return node_embedding_status_ok;
}),
AsFunctorRef<node_embedding_node_api_functor_ref>(
[&](node_embedding_runtime runtime, napi_env env) {
napi_value global, my_count;
NODE_API_CALL_RETURN_VOID(napi_get_global(env, &global));
NODE_API_CALL_RETURN_VOID(napi_get_named_property(
env, global, "myCount", &my_count));
int32_t count;
NODE_API_CALL_RETURN_VOID(
napi_get_value_int32(env, my_count, &count));
global_count.fetch_add(count);
})));
return node_embedding_status_ok;
}();
@ -116,25 +108,9 @@ extern "C" int32_t test_main_threading_several_runtimes_per_thread_node_api(
// process.
CHECK_STATUS(node_embedding_runtime_set_flags(
runtime_config,
node_embedding_runtime_default_flags |
node_embedding_runtime_no_create_inspector));
CHECK_STATUS(node_embedding_runtime_on_start_execution(
runtime_config,
AsFunctor<node_embedding_start_execution_functor>(
[](node_embedding_runtime runtime,
napi_env env,
napi_value process,
napi_value require,
napi_value run_cjs) -> napi_value {
napi_value script, undefined, result;
NODE_API_CALL(napi_create_string_utf8(
env, main_script, NAPI_AUTO_LENGTH, &script));
NODE_API_CALL(napi_get_undefined(env, &undefined));
NODE_API_CALL(napi_call_function(
env, undefined, run_cjs, 1, &script, &result));
return result;
})));
node_embedding_runtime_flags_default |
node_embedding_runtime_flags_no_create_inspector));
CHECK_STATUS(LoadUtf8Script(runtime_config, main_script));
return node_embedding_status_ok;
}),
&runtime));
@ -142,7 +118,7 @@ extern "C" int32_t test_main_threading_several_runtimes_per_thread_node_api(
CHECK_STATUS_OR_EXIT(node_embedding_run_node_api(
runtime,
AsFunctorRef<node_embedding_node_api_functor_ref>(
AsFunctorRef<node_embedding_run_node_api_functor_ref>(
[&](node_embedding_runtime runtime, napi_env env) {
napi_value undefined, global, func;
NODE_API_CALL_RETURN_VOID(napi_get_undefined(env, &undefined));
@ -163,7 +139,7 @@ extern "C" int32_t test_main_threading_several_runtimes_per_thread_node_api(
for (node_embedding_runtime runtime : runtimes) {
bool has_more_work = false;
CHECK_STATUS_OR_EXIT(node_embedding_run_event_loop(
runtime, node_embedding_event_loop_run_nowait, &has_more_work));
runtime, node_embedding_event_loop_run_mode_nowait, &has_more_work));
more_work |= has_more_work;
}
} while (more_work);
@ -171,7 +147,7 @@ extern "C" int32_t test_main_threading_several_runtimes_per_thread_node_api(
for (node_embedding_runtime runtime : runtimes) {
CHECK_STATUS_OR_EXIT(node_embedding_run_node_api(
runtime,
AsFunctorRef<node_embedding_node_api_functor_ref>(
AsFunctorRef<node_embedding_run_node_api_functor_ref>(
[&](node_embedding_runtime runtime, napi_env env) {
napi_value global, my_count;
NODE_API_CALL_RETURN_VOID(napi_get_global(env, &global));
@ -225,23 +201,7 @@ extern "C" int32_t test_main_threading_runtime_in_several_threads_node_api(
AsFunctorRef<node_embedding_configure_runtime_functor_ref>(
[&](node_embedding_platform platform,
node_embedding_runtime_config runtime_config) {
CHECK_STATUS(node_embedding_runtime_on_start_execution(
runtime_config,
AsFunctor<node_embedding_start_execution_functor>(
[](node_embedding_runtime runtime,
napi_env env,
napi_value process,
napi_value require,
napi_value run_cjs) -> napi_value {
napi_value script, undefined, result;
NODE_API_CALL(napi_create_string_utf8(
env, main_script, NAPI_AUTO_LENGTH, &script));
NODE_API_CALL(napi_get_undefined(env, &undefined));
NODE_API_CALL(napi_call_function(
env, undefined, run_cjs, 1, &script, &result));
return result;
})));
CHECK_STATUS(LoadUtf8Script(runtime_config, main_script));
return node_embedding_status_ok;
}),
&runtime));
@ -251,7 +211,7 @@ extern "C" int32_t test_main_threading_runtime_in_several_threads_node_api(
std::scoped_lock lock(mutex);
node_embedding_status status = node_embedding_run_node_api(
runtime,
AsFunctorRef<node_embedding_node_api_functor_ref>(
AsFunctorRef<node_embedding_run_node_api_functor_ref>(
[&](node_embedding_runtime runtime, napi_env env) {
napi_value undefined, global, func, my_count;
NODE_API_CALL_RETURN_VOID(napi_get_undefined(env, &undefined));
@ -359,21 +319,25 @@ extern "C" int32_t test_main_threading_runtime_in_ui_thread_node_api(
// The callback will be invoked from the runtime's event loop
// observer thread. It must schedule the work to the UI thread's
// event loop.
CHECK_STATUS(node_embedding_on_wake_up_event_loop(
CHECK_STATUS(node_embedding_runtime_set_task_runner(
runtime_config,
AsFunctor<node_embedding_event_loop_functor>(
[&ui_queue](node_embedding_runtime runtime) {
ui_queue.PostTask([runtime, &ui_queue]() {
CHECK_STATUS_OR_EXIT(node_embedding_run_event_loop(
runtime,
node_embedding_event_loop_run_nowait,
nullptr));
AsFunctor<node_embedding_post_task_functor>(
// We capture the ui_queue by reference here because we
// guarantee it to be alive till the end of the test. In
// real applications, you should use a safer way to capture
// the dispatcher queue.
[&ui_queue,
&runtime](node_embedding_run_task_functor run_task) {
// TODO: figure out the termination scenario.
ui_queue.PostTask([run_task, &runtime, &ui_queue]() {
AsStdFunction(run_task)();
// Check myCount and stop the processing when it
// reaches 5.
CHECK_STATUS_OR_EXIT(node_embedding_run_node_api(
runtime,
AsFunctorRef<node_embedding_node_api_functor_ref>(
AsFunctorRef<
node_embedding_run_node_api_functor_ref>(
[&](node_embedding_runtime runtime,
napi_env env) {
napi_value global, my_count;
@ -400,22 +364,7 @@ extern "C" int32_t test_main_threading_runtime_in_ui_thread_node_api(
});
})));
CHECK_STATUS(node_embedding_runtime_on_start_execution(
runtime_config,
AsFunctor<node_embedding_start_execution_functor>(
[](node_embedding_runtime runtime,
napi_env env,
napi_value process,
napi_value require,
napi_value run_cjs) -> napi_value {
napi_value script, undefined, result;
NODE_API_CALL(napi_create_string_utf8(
env, main_script, NAPI_AUTO_LENGTH, &script));
NODE_API_CALL(napi_get_undefined(env, &undefined));
NODE_API_CALL(napi_call_function(
env, undefined, run_cjs, 1, &script, &result));
return result;
})));
CHECK_STATUS(LoadUtf8Script(runtime_config, main_script));
return node_embedding_status_ok;
}),
@ -426,7 +375,7 @@ extern "C" int32_t test_main_threading_runtime_in_ui_thread_node_api(
ui_queue.PostTask([runtime]() {
node_embedding_status status = node_embedding_run_node_api(
runtime,
AsFunctorRef<node_embedding_node_api_functor_ref>(
AsFunctorRef<node_embedding_run_node_api_functor_ref>(
[&](node_embedding_runtime runtime, napi_env env) {
napi_value undefined, global, func;
NODE_API_CALL_RETURN_VOID(napi_get_undefined(env, &undefined));
@ -441,7 +390,7 @@ extern "C" int32_t test_main_threading_runtime_in_ui_thread_node_api(
env, undefined, func, 0, nullptr, nullptr));
node_embedding_run_event_loop(
runtime, node_embedding_event_loop_run_nowait, nullptr);
runtime, node_embedding_event_loop_run_mode_nowait, nullptr);
}));
CHECK_STATUS_OR_EXIT(status);
});

View File

@ -6,12 +6,23 @@ extern "C" int32_t test_main_nodejs_main_node_api(int32_t argc, char* argv[]);
extern "C" int32_t test_main_modules_node_api(int32_t argc, char* argv[]);
extern "C" int32_t test_main_linked_modules_node_api(int32_t argc,
char* argv[]);
extern "C" int32_t test_main_threading_runtime_per_thread_node_api(int32_t argc, char* argv[]);
extern "C" int32_t test_main_threading_several_runtimes_per_thread_node_api(int32_t argc, char* argv[]);
extern "C" int32_t test_main_threading_runtime_in_several_threads_node_api(int32_t argc, char* argv[]);
extern "C" int32_t test_main_threading_runtime_in_ui_thread_node_api(int32_t argc, char* argv[]);
extern "C" int32_t test_main_threading_runtime_per_thread_node_api(
int32_t argc, char* argv[]);
extern "C" int32_t test_main_threading_several_runtimes_per_thread_node_api(
int32_t argc, char* argv[]);
extern "C" int32_t test_main_threading_runtime_in_several_threads_node_api(
int32_t argc, char* argv[]);
extern "C" int32_t test_main_threading_runtime_in_ui_thread_node_api(
int32_t argc, char* argv[]);
extern "C" int32_t test_main_preload_node_api(int32_t argc, char* argv[]);
extern "C" int32_t test_main_c_api_env_no_browser_globals(int32_t argc,
char* argv[]);
extern "C" int32_t test_main_c_api_env_with_esm_loader(int32_t argc,
char* argv[]);
extern "C" int32_t test_main_c_api_env_with_no_esm_loader(int32_t argc,
char* argv[]);
typedef int32_t (*main_callback)(int32_t argc, char* argv[]);
int32_t CallWithoutArg1(main_callback main, int32_t argc, char** argv) {
@ -39,15 +50,29 @@ NODE_MAIN(int32_t argc, node::argv_type raw_argv[]) {
} else if (strcmp(arg1, "linked-modules-node-api") == 0) {
return CallWithoutArg1(test_main_linked_modules_node_api, argc, argv);
} else if (strcmp(arg1, "threading-runtime-per-thread-node-api") == 0) {
return CallWithoutArg1(test_main_threading_runtime_per_thread_node_api, argc, argv);
} else if (strcmp(arg1, "threading-several-runtimes-per-thread-node-api") == 0) {
return CallWithoutArg1(test_main_threading_several_runtimes_per_thread_node_api, argc, argv);
} else if (strcmp(arg1, "threading-runtime-in-several-threads-node-api") == 0) {
return CallWithoutArg1(test_main_threading_runtime_in_several_threads_node_api, argc, argv);
return CallWithoutArg1(
test_main_threading_runtime_per_thread_node_api, argc, argv);
} else if (strcmp(arg1, "threading-several-runtimes-per-thread-node-api") ==
0) {
return CallWithoutArg1(
test_main_threading_several_runtimes_per_thread_node_api, argc, argv);
} else if (strcmp(arg1, "threading-runtime-in-several-threads-node-api") ==
0) {
return CallWithoutArg1(
test_main_threading_runtime_in_several_threads_node_api, argc, argv);
} else if (strcmp(arg1, "threading-runtime-in-ui-thread-node-api") == 0) {
return CallWithoutArg1(test_main_threading_runtime_in_ui_thread_node_api, argc, argv);
return CallWithoutArg1(
test_main_threading_runtime_in_ui_thread_node_api, argc, argv);
} else if (strcmp(arg1, "preload-node-api") == 0) {
return CallWithoutArg1(test_main_preload_node_api, argc, argv);
} else if (strcmp(arg1, "c-api-env-no-browser-globals") == 0) {
return CallWithoutArg1(
test_main_c_api_env_no_browser_globals, argc, argv);
} else if (strcmp(arg1, "c-api-env-with-esm-loader") == 0) {
return CallWithoutArg1(test_main_c_api_env_with_esm_loader, argc, argv);
} else if (strcmp(arg1, "c-api-env-with-no-esm-loader") == 0) {
return CallWithoutArg1(
test_main_c_api_env_with_no_esm_loader, argc, argv);
}
}
return test_main_cpp_api(argc, argv);

View File

@ -383,6 +383,34 @@ runSnapshotTests('cpp-api');
);
}
function runEnvTests(apiType) {
runTest(
`${apiType}: Env No Browser Globals`,
spawnSyncAndExitWithoutError,
[`${apiType}-env-no-browser-globals`],
{}
);
runTest(
`${apiType}: Env With ESM Loader`,
spawnSyncAndExitWithoutError,
[`${apiType}-env-with-esm-loader`],
{}
);
runTest(
`${apiType}: Env With No ESM Loader`,
spawnSyncAndExit,
[`${apiType}-env-with-no-esm-loader`],
{
status: 1,
signal: null,
}
);
}
runEnvTests('c-api');
/*
runTest(
`modules-node-api: load modules`,