mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +01:00
n-api: add helper for addons to get the event loop
Add a utility functions for addons to use when they need a reference to the current event loop. While the libuv API is not directly part of N-API, it provides a quite stable C API as well, and is tightly integrated with Node itself. As a particular use case, without access to the event loop it is hard to do something interesting from inside a N-API finalizer function, since calls into JS and therefore virtually all other N-API functions are not allowed. Backport-PR-URL: https://github.com/nodejs/node/pull/19447 PR-URL: https://github.com/nodejs/node/pull/17109 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
35dc8bab9e
commit
f4391b95ee
|
|
@ -3684,6 +3684,23 @@ NAPI_EXTERN napi_status napi_run_script(napi_env env,
|
|||
- `[in] script`: A JavaScript string containing the script to execute.
|
||||
- `[out] result`: The value resulting from having executed the script.
|
||||
|
||||
## libuv event loop
|
||||
|
||||
N-API provides a function for getting the current event loop associated with
|
||||
a specific `napi_env`.
|
||||
|
||||
### napi_get_uv_event_loop
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
```C
|
||||
NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env,
|
||||
uv_loop_t** loop);
|
||||
```
|
||||
|
||||
- `[in] env`: The environment that the API is invoked under.
|
||||
- `[out] loop`: The current libuv loop instance.
|
||||
|
||||
[Promises]: #n_api_promises
|
||||
[Simple Asynchronous Operations]: #n_api_simple_asynchronous_operations
|
||||
[Custom Asynchronous Operations]: #n_api_custom_asynchronous_operations
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include "node_api_backport.h"
|
||||
#include "util.h"
|
||||
|
||||
#define NAPI_VERSION 1
|
||||
#define NAPI_VERSION 2
|
||||
|
||||
static
|
||||
napi_status napi_set_last_error(napi_env env, napi_status error_code,
|
||||
|
|
@ -31,8 +31,11 @@ napi_status napi_set_last_error(napi_env env, napi_status error_code,
|
|||
static napi_status napi_clear_last_error(napi_env env);
|
||||
|
||||
struct napi_env__ {
|
||||
explicit napi_env__(v8::Isolate* _isolate): isolate(_isolate),
|
||||
has_instance_available(true), last_error() {}
|
||||
explicit napi_env__(v8::Isolate* _isolate, uv_loop_t *_loop):
|
||||
isolate(_isolate),
|
||||
has_instance_available(true),
|
||||
last_error(),
|
||||
loop(_loop) {}
|
||||
~napi_env__() {
|
||||
last_exception.Reset();
|
||||
has_instance.Reset();
|
||||
|
|
@ -49,6 +52,7 @@ struct napi_env__ {
|
|||
bool has_instance_available;
|
||||
napi_extended_error_info last_error;
|
||||
int open_handle_scopes = 0;
|
||||
uv_loop_t* loop = nullptr;
|
||||
};
|
||||
|
||||
#define ENV_OBJECT_TEMPLATE(env, prefix, destination, field_count) \
|
||||
|
|
@ -780,7 +784,7 @@ napi_env GetEnv(v8::Local<v8::Context> context) {
|
|||
if (value->IsExternal()) {
|
||||
result = static_cast<napi_env>(value.As<v8::External>()->Value());
|
||||
} else {
|
||||
result = new napi_env__(isolate);
|
||||
result = new napi_env__(isolate, node::GetCurrentEventLoop(isolate));
|
||||
auto external = v8::External::New(isolate, result);
|
||||
|
||||
// We must also stop hard if the result of assigning the env to the global
|
||||
|
|
@ -3494,15 +3498,22 @@ napi_status napi_delete_async_work(napi_env env, napi_async_work work) {
|
|||
return napi_clear_last_error(env);
|
||||
}
|
||||
|
||||
napi_status napi_get_uv_event_loop(napi_env env, uv_loop_t** loop) {
|
||||
CHECK_ENV(env);
|
||||
CHECK_ARG(env, loop);
|
||||
*loop = env->loop;
|
||||
return napi_clear_last_error(env);
|
||||
}
|
||||
|
||||
napi_status napi_queue_async_work(napi_env env, napi_async_work work) {
|
||||
CHECK_ENV(env);
|
||||
CHECK_ARG(env, work);
|
||||
|
||||
// Consider: Encapsulate the uv_loop_t into an opaque pointer parameter.
|
||||
// Currently the environment event loop is the same as the UV default loop.
|
||||
// Someday (if node ever supports multiple isolates), it may be better to get
|
||||
// the loop from node::Environment::GetCurrent(env->isolate)->event_loop();
|
||||
uv_loop_t* event_loop = uv_default_loop();
|
||||
napi_status status;
|
||||
uv_loop_t* event_loop = nullptr;
|
||||
status = napi_get_uv_event_loop(env, &event_loop);
|
||||
if (status != napi_ok)
|
||||
return napi_set_last_error(env, status);
|
||||
|
||||
uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include <stdbool.h>
|
||||
#include "node_api_types.h"
|
||||
|
||||
struct uv_loop_s; // Forward declaration.
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef BUILDING_NODE_EXTENSION
|
||||
#ifdef EXTERNAL_NAPI
|
||||
|
|
@ -581,6 +583,10 @@ NAPI_EXTERN napi_status napi_run_script(napi_env env,
|
|||
napi_value script,
|
||||
napi_value* result);
|
||||
|
||||
// Return the current libuv event loop for a given environment
|
||||
NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env,
|
||||
struct uv_loop_s** loop);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif // SRC_NODE_API_H_
|
||||
|
|
|
|||
|
|
@ -71,6 +71,14 @@ CallbackScope::~CallbackScope() {
|
|||
env->tick_callback_function()->Call(env->process_object(), 0, nullptr);
|
||||
}
|
||||
|
||||
uv_loop_t *GetCurrentEventLoop(v8::Isolate *isolate) {
|
||||
HandleScope handle_scope(isolate);
|
||||
auto context = isolate->GetCurrentContext();
|
||||
if (context.IsEmpty())
|
||||
return nullptr;
|
||||
return Environment::GetCurrent(context)->event_loop();
|
||||
}
|
||||
|
||||
AsyncResource::AsyncResource(v8::Isolate* _isolate,
|
||||
v8::Local<v8::Object> _object,
|
||||
char* name) : isolate(_isolate) {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ class CallbackScope {
|
|||
Environment::AsyncCallbackScope callback_scope;
|
||||
};
|
||||
|
||||
uv_loop_t *GetCurrentEventLoop(v8::Isolate *isolate);
|
||||
|
||||
NODE_EXTERN async_context EmitAsyncInit(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> resource,
|
||||
v8::Local<v8::String> name,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ assert.ok(test_general.testGetPrototype(baseObject) !==
|
|||
|
||||
// test version management funcitons
|
||||
// expected version is currently 1
|
||||
assert.strictEqual(test_general.testGetVersion(), 1);
|
||||
assert.strictEqual(test_general.testGetVersion(), 2);
|
||||
|
||||
const [ major, minor, patch, release ] = test_general.testGetNodeVersion();
|
||||
assert.strictEqual(process.version.split('-')[0],
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user