Browse Source

async_hooks: implement C++ embedder API

PR-URL: https://github.com/nodejs/node/pull/13142
Reviewed-By: Matthew Loring <mattloring@google.com>
Reviewed-By: Andreas Madsen <amwebdk@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
v6
Anna Henningsen 8 years ago
parent
commit
a86323dc64
No known key found for this signature in database GPG Key ID: D8B9F5AEAE84E4CF
  1. 121
      src/async-wrap.cc
  2. 9
      src/async-wrap.h
  3. 4
      src/inspector_agent.cc
  4. 200
      src/node.cc
  5. 133
      src/node.h
  6. 6
      src/node_crypto.cc
  7. 21
      src/node_internals.h

121
src/async-wrap.cc

@ -47,6 +47,7 @@ using v8::Object;
using v8::Promise; using v8::Promise;
using v8::PromiseHookType; using v8::PromiseHookType;
using v8::RetainedObjectInfo; using v8::RetainedObjectInfo;
using v8::String;
using v8::Symbol; using v8::Symbol;
using v8::TryCatch; using v8::TryCatch;
using v8::Uint32Array; using v8::Uint32Array;
@ -216,23 +217,28 @@ bool DomainExit(Environment* env, v8::Local<v8::Object> object) {
static bool PreCallbackExecution(AsyncWrap* wrap, bool run_domain_cbs) { static bool PreCallbackExecution(AsyncWrap* wrap, bool run_domain_cbs) {
AsyncHooks* async_hooks = wrap->env()->async_hooks();
if (wrap->env()->using_domains() && run_domain_cbs) { if (wrap->env()->using_domains() && run_domain_cbs) {
bool is_disposed = DomainEnter(wrap->env(), wrap->object()); bool is_disposed = DomainEnter(wrap->env(), wrap->object());
if (is_disposed) if (is_disposed)
return false; return false;
} }
return AsyncWrap::EmitBefore(wrap->env(), wrap->get_id());
}
bool AsyncWrap::EmitBefore(Environment* env, double async_id) {
AsyncHooks* async_hooks = env->async_hooks();
if (async_hooks->fields()[AsyncHooks::kBefore] > 0) { if (async_hooks->fields()[AsyncHooks::kBefore] > 0) {
Local<Value> uid = Number::New(wrap->env()->isolate(), wrap->get_id()); Local<Value> uid = Number::New(env->isolate(), async_id);
Local<Function> fn = wrap->env()->async_hooks_before_function(); Local<Function> fn = env->async_hooks_before_function();
TryCatch try_catch(wrap->env()->isolate()); TryCatch try_catch(env->isolate());
MaybeLocal<Value> ar = fn->Call( MaybeLocal<Value> ar = fn->Call(
wrap->env()->context(), Undefined(wrap->env()->isolate()), 1, &uid); env->context(), Undefined(env->isolate()), 1, &uid);
if (ar.IsEmpty()) { if (ar.IsEmpty()) {
ClearFatalExceptionHandlers(wrap->env()); ClearFatalExceptionHandlers(env);
FatalException(wrap->env()->isolate(), try_catch); FatalException(env->isolate(), try_catch);
return false; return false;
} }
} }
@ -242,29 +248,36 @@ static bool PreCallbackExecution(AsyncWrap* wrap, bool run_domain_cbs) {
static bool PostCallbackExecution(AsyncWrap* wrap, bool run_domain_cbs) { static bool PostCallbackExecution(AsyncWrap* wrap, bool run_domain_cbs) {
AsyncHooks* async_hooks = wrap->env()->async_hooks(); if (!AsyncWrap::EmitAfter(wrap->env(), wrap->get_id()))
return false;
if (wrap->env()->using_domains() && run_domain_cbs) {
bool is_disposed = DomainExit(wrap->env(), wrap->object());
if (is_disposed)
return false;
}
return true;
}
bool AsyncWrap::EmitAfter(Environment* env, double async_id) {
AsyncHooks* async_hooks = env->async_hooks();
// If the callback failed then the after() hooks will be called at the end // If the callback failed then the after() hooks will be called at the end
// of _fatalException(). // of _fatalException().
if (async_hooks->fields()[AsyncHooks::kAfter] > 0) { if (async_hooks->fields()[AsyncHooks::kAfter] > 0) {
Local<Value> uid = Number::New(wrap->env()->isolate(), wrap->get_id()); Local<Value> uid = Number::New(env->isolate(), async_id);
Local<Function> fn = wrap->env()->async_hooks_after_function(); Local<Function> fn = env->async_hooks_after_function();
TryCatch try_catch(wrap->env()->isolate()); TryCatch try_catch(env->isolate());
MaybeLocal<Value> ar = fn->Call( MaybeLocal<Value> ar = fn->Call(
wrap->env()->context(), Undefined(wrap->env()->isolate()), 1, &uid); env->context(), Undefined(env->isolate()), 1, &uid);
if (ar.IsEmpty()) { if (ar.IsEmpty()) {
ClearFatalExceptionHandlers(wrap->env()); ClearFatalExceptionHandlers(env);
FatalException(wrap->env()->isolate(), try_catch); FatalException(env->isolate(), try_catch);
return false; return false;
} }
} }
if (wrap->env()->using_domains() && run_domain_cbs) {
bool is_disposed = DomainExit(wrap->env(), wrap->object());
if (is_disposed)
return false;
}
return true; return true;
} }
@ -526,32 +539,44 @@ AsyncWrap::~AsyncWrap() {
// and reused over their lifetime. This way a new uid can be assigned when // and reused over their lifetime. This way a new uid can be assigned when
// the resource is pulled out of the pool and put back into use. // the resource is pulled out of the pool and put back into use.
void AsyncWrap::AsyncReset() { void AsyncWrap::AsyncReset() {
AsyncHooks* async_hooks = env()->async_hooks();
async_id_ = env()->new_async_id(); async_id_ = env()->new_async_id();
trigger_id_ = env()->get_init_trigger_id(); trigger_id_ = env()->get_init_trigger_id();
EmitAsyncInit(env(), object(),
env()->async_hooks()->provider_string(provider_type()),
async_id_, trigger_id_);
}
void AsyncWrap::EmitAsyncInit(Environment* env,
Local<Object> object,
Local<String> type,
double async_id,
double trigger_id) {
AsyncHooks* async_hooks = env->async_hooks();
// Nothing to execute, so can continue normally. // Nothing to execute, so can continue normally.
if (async_hooks->fields()[AsyncHooks::kInit] == 0) { if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
return; return;
} }
HandleScope scope(env()->isolate()); HandleScope scope(env->isolate());
Local<Function> init_fn = env()->async_hooks_init_function(); Local<Function> init_fn = env->async_hooks_init_function();
Local<Value> argv[] = { Local<Value> argv[] = {
Number::New(env()->isolate(), get_id()), Number::New(env->isolate(), async_id),
env()->async_hooks()->provider_string(provider_type()), type,
object(), object,
Number::New(env()->isolate(), get_trigger_id()), Number::New(env->isolate(), trigger_id),
}; };
TryCatch try_catch(env()->isolate()); TryCatch try_catch(env->isolate());
MaybeLocal<Value> ret = init_fn->Call( MaybeLocal<Value> ret = init_fn->Call(
env()->context(), object(), arraysize(argv), argv); env->context(), object, arraysize(argv), argv);
if (ret.IsEmpty()) { if (ret.IsEmpty()) {
ClearFatalExceptionHandlers(env()); ClearFatalExceptionHandlers(env);
FatalException(env()->isolate(), try_catch); FatalException(env->isolate(), try_catch);
} }
} }
@ -620,6 +645,38 @@ Local<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
return rcheck.IsEmpty() ? Local<Value>() : ret_v; return rcheck.IsEmpty() ? Local<Value>() : ret_v;
} }
/* Public C++ embedder API */
async_uid AsyncHooksGetCurrentId(Isolate* isolate) {
return Environment::GetCurrent(isolate)->current_async_id();
}
async_uid AsyncHooksGetTriggerId(Isolate* isolate) {
return Environment::GetCurrent(isolate)->get_init_trigger_id();
}
async_uid EmitAsyncInit(Isolate* isolate,
Local<Object> resource,
const char* name,
async_uid trigger_id) {
Environment* env = Environment::GetCurrent(isolate);
async_uid async_id = env->new_async_id();
Local<String> type =
String::NewFromUtf8(isolate, name, v8::NewStringType::kInternalized)
.ToLocalChecked();
AsyncWrap::EmitAsyncInit(env, resource, type, async_id, trigger_id);
return async_id;
}
void EmitAsyncDestroy(Isolate* isolate, async_uid id) {
PushBackDestroyId(Environment::GetCurrent(isolate), id);
}
} // namespace node } // namespace node
NODE_MODULE_CONTEXT_AWARE_BUILTIN(async_wrap, node::AsyncWrap::Initialize) NODE_MODULE_CONTEXT_AWARE_BUILTIN(async_wrap, node::AsyncWrap::Initialize)

9
src/async-wrap.h

@ -101,6 +101,15 @@ class AsyncWrap : public BaseObject {
static void AsyncReset(const v8::FunctionCallbackInfo<v8::Value>& args); static void AsyncReset(const v8::FunctionCallbackInfo<v8::Value>& args);
static void QueueDestroyId(const v8::FunctionCallbackInfo<v8::Value>& args); static void QueueDestroyId(const v8::FunctionCallbackInfo<v8::Value>& args);
static void EmitAsyncInit(Environment* env,
v8::Local<v8::Object> object,
v8::Local<v8::String> type,
double id,
double trigger_id);
static bool EmitBefore(Environment* env, double id);
static bool EmitAfter(Environment* env, double id);
inline ProviderType provider_type() const; inline ProviderType provider_type() const;
inline double get_id() const; inline double get_id() const;

4
src/inspector_agent.cc

@ -597,8 +597,8 @@ bool Agent::StartIoThread(bool wait_for_connect) {
FIXED_ONE_BYTE_STRING(isolate, "internalMessage"), FIXED_ONE_BYTE_STRING(isolate, "internalMessage"),
message message
}; };
MakeCallback(parent_env_, process_object.As<Value>(), emit_fn.As<Function>(), MakeCallback(parent_env_->isolate(), process_object, emit_fn.As<Function>(),
arraysize(argv), argv); arraysize(argv), argv, 0, 0);
return true; return true;
} }

200
src/node.cc

@ -348,7 +348,12 @@ static void CheckImmediate(uv_check_t* handle) {
Environment* env = Environment::from_immediate_check_handle(handle); Environment* env = Environment::from_immediate_check_handle(handle);
HandleScope scope(env->isolate()); HandleScope scope(env->isolate());
Context::Scope context_scope(env->context()); Context::Scope context_scope(env->context());
MakeCallback(env, env->process_object(), env->immediate_callback_string()); MakeCallback(env->isolate(),
env->process_object(),
env->immediate_callback_string(),
0,
nullptr,
0, 0).ToLocalChecked();
} }
@ -1281,18 +1286,20 @@ void AddPromiseHook(v8::Isolate* isolate, promise_hook_func fn, void* arg) {
} }
Local<Value> MakeCallback(Environment* env, MaybeLocal<Value> MakeCallback(Environment* env,
Local<Value> recv, Local<Value> recv,
const Local<Function> callback, const Local<Function> callback,
int argc, int argc,
Local<Value> argv[]) { Local<Value> argv[],
double async_id,
double trigger_id) {
// If you hit this assertion, you forgot to enter the v8::Context first. // If you hit this assertion, you forgot to enter the v8::Context first.
CHECK_EQ(env->context(), env->isolate()->GetCurrentContext()); CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
Local<Object> object, domain; Local<Object> object;
bool has_domain = false;
Environment::AsyncCallbackScope callback_scope(env); Environment::AsyncCallbackScope callback_scope(env);
bool disposed_domain = false;
if (recv->IsObject()) { if (recv->IsObject()) {
object = recv.As<Object>(); object = recv.As<Object>();
@ -1300,51 +1307,38 @@ Local<Value> MakeCallback(Environment* env,
if (env->using_domains()) { if (env->using_domains()) {
CHECK(recv->IsObject()); CHECK(recv->IsObject());
Local<Value> domain_v = object->Get(env->domain_string()); disposed_domain = DomainEnter(env, object);
has_domain = domain_v->IsObject(); if (disposed_domain) return Undefined(env->isolate());
if (has_domain) {
domain = domain_v.As<Object>();
if (domain->Get(env->disposed_string())->IsTrue())
return Undefined(env->isolate());
}
} }
if (has_domain) { MaybeLocal<Value> ret;
Local<Value> enter_v = domain->Get(env->enter_string());
if (enter_v->IsFunction()) {
if (enter_v.As<Function>()->Call(domain, 0, nullptr).IsEmpty()) {
FatalError("node::MakeCallback",
"domain enter callback threw, please report this");
}
}
}
// TODO(trevnorris): Correct this once node::MakeCallback() support id and {
// triggerId. Consider completely removing it until then so the async id can AsyncHooks::ExecScope exec_scope(env, async_id, trigger_id);
// propagate through to the fatalException after hook calls.
AsyncHooks::ExecScope exec_scope(env, 0, 0);
Local<Value> ret = callback->Call(recv, argc, argv); if (async_id != 0) {
if (!AsyncWrap::EmitBefore(env, async_id)) return Local<Value>();
}
if (ret.IsEmpty()) { ret = callback->Call(env->context(), recv, argc, argv);
// NOTE: For backwards compatibility with public API we return Undefined()
// if the top level call threw.
return callback_scope.in_makecallback() ?
ret : Undefined(env->isolate()).As<Value>();
}
exec_scope.Dispose(); if (ret.IsEmpty()) {
// NOTE: For backwards compatibility with public API we return Undefined()
// if the top level call threw.
return callback_scope.in_makecallback() ?
ret : Undefined(env->isolate());
}
if (has_domain) { if (async_id != 0) {
Local<Value> exit_v = domain->Get(env->exit_string()); if (!AsyncWrap::EmitAfter(env, async_id)) return Local<Value>();
if (exit_v->IsFunction()) {
if (exit_v.As<Function>()->Call(domain, 0, nullptr).IsEmpty()) {
FatalError("node::MakeCallback",
"domain exit callback threw, please report this");
}
} }
} }
if (env->using_domains()) {
disposed_domain = DomainExit(env, object);
if (disposed_domain) return Undefined(env->isolate());
}
if (callback_scope.in_makecallback()) { if (callback_scope.in_makecallback()) {
return ret; return ret;
} }
@ -1357,8 +1351,8 @@ Local<Value> MakeCallback(Environment* env,
// Make sure the stack unwound properly. If there are nested MakeCallback's // Make sure the stack unwound properly. If there are nested MakeCallback's
// then it should return early and not reach this code. // then it should return early and not reach this code.
CHECK_EQ(env->current_async_id(), 0); CHECK_EQ(env->current_async_id(), async_id);
CHECK_EQ(env->trigger_id(), 0); CHECK_EQ(env->trigger_id(), trigger_id);
Local<Object> process = env->process_object(); Local<Object> process = env->process_object();
@ -1375,70 +1369,96 @@ Local<Value> MakeCallback(Environment* env,
} }
Local<Value> MakeCallback(Environment* env, // Public MakeCallback()s
Local<Object> recv,
Local<String> symbol,
int argc, MaybeLocal<Value> MakeCallback(Isolate* isolate,
Local<Value> argv[]) { Local<Object> recv,
Local<Value> cb_v = recv->Get(symbol); const char* method,
CHECK(cb_v->IsFunction()); int argc,
return MakeCallback(env, recv.As<Value>(), cb_v.As<Function>(), argc, argv); Local<Value> argv[],
async_uid async_id,
async_uid trigger_id) {
Local<String> method_string =
String::NewFromUtf8(isolate, method, v8::NewStringType::kNormal)
.ToLocalChecked();
return MakeCallback(isolate, recv, method_string, argc, argv,
async_id, trigger_id);
} }
Local<Value> MakeCallback(Environment* env, MaybeLocal<Value> MakeCallback(Isolate* isolate,
Local<Object> recv, Local<Object> recv,
const char* method, Local<String> symbol,
int argc, int argc,
Local<Value> argv[]) { Local<Value> argv[],
Local<String> method_string = OneByteString(env->isolate(), method); async_uid async_id,
return MakeCallback(env, recv, method_string, argc, argv); async_uid trigger_id) {
Local<Value> callback_v = recv->Get(symbol);
if (callback_v.IsEmpty()) return Local<Value>();
if (!callback_v->IsFunction()) return Local<Value>();
Local<Function> callback = callback_v.As<Function>();
return MakeCallback(isolate, recv, callback, argc, argv,
async_id, trigger_id);
} }
MaybeLocal<Value> MakeCallback(Isolate* isolate,
Local<Object> recv,
Local<Function> callback,
int argc,
Local<Value> argv[],
async_uid async_id,
async_uid trigger_id) {
// Observe the following two subtleties:
//
// 1. The environment is retrieved from the callback function's context.
// 2. The context to enter is retrieved from the environment.
//
// Because of the AssignToContext() call in src/node_contextify.cc,
// the two contexts need not be the same.
Environment* env = Environment::GetCurrent(callback->CreationContext());
Context::Scope context_scope(env->context());
return MakeCallback(env, recv.As<Value>(), callback, argc, argv,
async_id, trigger_id);
}
// Legacy MakeCallback()s
Local<Value> MakeCallback(Isolate* isolate, Local<Value> MakeCallback(Isolate* isolate,
Local<Object> recv, Local<Object> recv,
const char* method, const char* method,
int argc, int argc,
Local<Value> argv[]) { Local<Value>* argv) {
EscapableHandleScope handle_scope(isolate); EscapableHandleScope handle_scope(isolate);
Local<String> method_string = OneByteString(isolate, method);
return handle_scope.Escape( return handle_scope.Escape(
MakeCallback(isolate, recv, method_string, argc, argv)); MakeCallback(isolate, recv, method, argc, argv, 0, 0)
.FromMaybe(Local<Value>()));
} }
Local<Value> MakeCallback(Isolate* isolate, Local<Value> MakeCallback(Isolate* isolate,
Local<Object> recv, Local<Object> recv,
Local<String> symbol, Local<String> symbol,
int argc, int argc,
Local<Value> argv[]) { Local<Value>* argv) {
EscapableHandleScope handle_scope(isolate); EscapableHandleScope handle_scope(isolate);
Local<Value> callback_v = recv->Get(symbol); return handle_scope.Escape(
if (callback_v.IsEmpty()) return Local<Value>(); MakeCallback(isolate, recv, symbol, argc, argv, 0, 0)
if (!callback_v->IsFunction()) return Local<Value>(); .FromMaybe(Local<Value>()));
Local<Function> callback = callback_v.As<Function>();
return handle_scope.Escape(MakeCallback(isolate, recv, callback, argc, argv));
} }
Local<Value> MakeCallback(Isolate* isolate, Local<Value> MakeCallback(Isolate* isolate,
Local<Object> recv, Local<Object> recv,
Local<Function> callback, Local<Function> callback,
int argc, int argc,
Local<Value> argv[]) { Local<Value>* argv) {
// Observe the following two subtleties:
//
// 1. The environment is retrieved from the callback function's context.
// 2. The context to enter is retrieved from the environment.
//
// Because of the AssignToContext() call in src/node_contextify.cc,
// the two contexts need not be the same.
EscapableHandleScope handle_scope(isolate); EscapableHandleScope handle_scope(isolate);
Environment* env = Environment::GetCurrent(callback->CreationContext());
Context::Scope context_scope(env->context());
return handle_scope.Escape( return handle_scope.Escape(
MakeCallback(env, recv.As<Value>(), callback, argc, argv)); MakeCallback(isolate, recv, callback, argc, argv, 0, 0)
.FromMaybe(Local<Value>()));
} }
@ -4382,7 +4402,9 @@ void EmitBeforeExit(Environment* env) {
FIXED_ONE_BYTE_STRING(env->isolate(), "beforeExit"), FIXED_ONE_BYTE_STRING(env->isolate(), "beforeExit"),
process_object->Get(exit_code)->ToInteger(env->isolate()) process_object->Get(exit_code)->ToInteger(env->isolate())
}; };
MakeCallback(env, process_object, "emit", arraysize(args), args); MakeCallback(env->isolate(),
process_object, "emit", arraysize(args), args,
0, 0).ToLocalChecked();
} }
@ -4401,7 +4423,9 @@ int EmitExit(Environment* env) {
Integer::New(env->isolate(), code) Integer::New(env->isolate(), code)
}; };
MakeCallback(env, process_object, "emit", arraysize(args), args); MakeCallback(env->isolate(),
process_object, "emit", arraysize(args), args,
0, 0).ToLocalChecked();
// Reload exit code, it may be changed by `emit('exit')` // Reload exit code, it may be changed by `emit('exit')`
return process_object->Get(exitCode)->Int32Value(); return process_object->Get(exitCode)->Int32Value();

133
src/node.h

@ -142,14 +142,10 @@ inline v8::Local<v8::Value> UVException(int errorno,
} }
/* /*
* MakeCallback doesn't have a HandleScope. That means the callers scope * These methods need to be called in a HandleScope.
* will retain ownership of created handles from MakeCallback and related.
* There is by default a wrapping HandleScope before uv_run, if the caller
* doesn't have a HandleScope on the stack the global will take ownership
* which won't be reaped until the uv loop exits.
* *
* If a uv callback is fired, and there is no enclosing HandleScope in the * It is preferred that you use the `MakeCallback` overloads taking
* cb, you will appear to leak 4-bytes for every invocation. Take heed. * `async_uid` arguments.
*/ */
NODE_EXTERN v8::Local<v8::Value> MakeCallback( NODE_EXTERN v8::Local<v8::Value> MakeCallback(
@ -521,12 +517,135 @@ typedef void (*promise_hook_func) (v8::PromiseHookType type,
v8::Local<v8::Value> parent, v8::Local<v8::Value> parent,
void* arg); void* arg);
typedef double async_uid;
/* Registers an additional v8::PromiseHook wrapper. This API exists because V8 /* Registers an additional v8::PromiseHook wrapper. This API exists because V8
* itself supports only a single PromiseHook. */ * itself supports only a single PromiseHook. */
NODE_EXTERN void AddPromiseHook(v8::Isolate* isolate, NODE_EXTERN void AddPromiseHook(v8::Isolate* isolate,
promise_hook_func fn, promise_hook_func fn,
void* arg); void* arg);
/* Returns the id of the current execution context. If the return value is
* zero then no execution has been set. This will happen if the user handles
* I/O from native code. */
NODE_EXTERN async_uid AsyncHooksGetCurrentId(v8::Isolate* isolate);
/* Return same value as async_hooks.triggerId(); */
NODE_EXTERN async_uid AsyncHooksGetTriggerId(v8::Isolate* isolate);
/* If the native API doesn't inherit from the helper class then the callbacks
* must be triggered manually. This triggers the init() callback. The return
* value is the uid assigned to the resource.
*
* The `trigger_id` parameter should correspond to the resource which is
* creating the new resource, which will usually be the return value of
* `AsyncHooksGetTriggerId()`. */
NODE_EXTERN async_uid EmitAsyncInit(v8::Isolate* isolate,
v8::Local<v8::Object> resource,
const char* name,
async_uid trigger_id);
/* Emit the destroy() callback. */
NODE_EXTERN void EmitAsyncDestroy(v8::Isolate* isolate, async_uid id);
/* An API specific to emit before/after callbacks is unnecessary because
* MakeCallback will automatically call them for you.
*
* These methods may create handles on their own, so run them inside a
* HandleScope.
*
* `asyncId` and `triggerId` should correspond to the values returned by
* `EmitAsyncInit()` and `AsyncHooksGetTriggerId()`, respectively, when the
* invoking resource was created. If these values are unknown, 0 can be passed.
* */
NODE_EXTERN
v8::MaybeLocal<v8::Value> MakeCallback(v8::Isolate* isolate,
v8::Local<v8::Object> recv,
v8::Local<v8::Function> callback,
int argc,
v8::Local<v8::Value>* argv,
async_uid asyncId,
async_uid triggerId);
NODE_EXTERN
v8::MaybeLocal<v8::Value> MakeCallback(v8::Isolate* isolate,
v8::Local<v8::Object> recv,
const char* method,
int argc,
v8::Local<v8::Value>* argv,
async_uid asyncId,
async_uid triggerId);
NODE_EXTERN
v8::MaybeLocal<v8::Value> MakeCallback(v8::Isolate* isolate,
v8::Local<v8::Object> recv,
v8::Local<v8::String> symbol,
int argc,
v8::Local<v8::Value>* argv,
async_uid asyncId,
async_uid triggerId);
/* Helper class users can optionally inherit from. If
* `AsyncResource::MakeCallback()` is used, then all four callbacks will be
* called automatically. */
class AsyncResource {
public:
AsyncResource(v8::Isolate* isolate,
v8::Local<v8::Object> resource,
const char* name,
async_uid trigger_id = -1)
: isolate_(isolate),
resource_(isolate, resource),
trigger_id_(trigger_id) {
if (trigger_id_ == -1)
trigger_id_ = AsyncHooksGetTriggerId(isolate);
uid_ = EmitAsyncInit(isolate, resource, name, trigger_id_);
}
~AsyncResource() {
EmitAsyncDestroy(isolate_, uid_);
}
v8::MaybeLocal<v8::Value> MakeCallback(
v8::Local<v8::Function> callback,
int argc,
v8::Local<v8::Value>* argv) {
return node::MakeCallback(isolate_, get_resource(),
callback, argc, argv,
uid_, trigger_id_);
}
v8::MaybeLocal<v8::Value> MakeCallback(
const char* method,
int argc,
v8::Local<v8::Value>* argv) {
return node::MakeCallback(isolate_, get_resource(),
method, argc, argv,
uid_, trigger_id_);
}
v8::MaybeLocal<v8::Value> MakeCallback(
v8::Local<v8::String> symbol,
int argc,
v8::Local<v8::Value>* argv) {
return node::MakeCallback(isolate_, get_resource(),
symbol, argc, argv,
uid_, trigger_id_);
}
v8::Local<v8::Object> get_resource() {
return resource_.Get(isolate_);
}
async_uid get_uid() const {
return uid_;
}
private:
v8::Isolate* isolate_;
v8::Persistent<v8::Object> resource_;
async_uid uid_;
async_uid trigger_id_;
};
} // namespace node } // namespace node
#endif // SRC_NODE_H_ #endif // SRC_NODE_H_

6
src/node_crypto.cc

@ -1237,11 +1237,13 @@ int SecureContext::TicketKeyCallback(SSL* ssl,
kTicketPartSize).ToLocalChecked(), kTicketPartSize).ToLocalChecked(),
Boolean::New(env->isolate(), enc != 0) Boolean::New(env->isolate(), enc != 0)
}; };
Local<Value> ret = node::MakeCallback(env,
Local<Value> ret = node::MakeCallback(env->isolate(),
sc->object(), sc->object(),
env->ticketkeycallback_string(), env->ticketkeycallback_string(),
arraysize(argv), arraysize(argv),
argv); argv,
0, 0).ToLocalChecked();
Local<Array> arr = ret.As<Array>(); Local<Array> arr = ret.As<Array>();
int r = arr->Get(kTicketKeyReturnIndex)->Int32Value(); int r = arr->Get(kTicketKeyReturnIndex)->Int32Value();

21
src/node_internals.h

@ -94,27 +94,6 @@ inline v8::Local<TypeName> PersistentToLocal(
v8::Isolate* isolate, v8::Isolate* isolate,
const v8::Persistent<TypeName>& persistent); const v8::Persistent<TypeName>& persistent);
// Call with valid HandleScope and while inside Context scope.
v8::Local<v8::Value> MakeCallback(Environment* env,
v8::Local<v8::Object> recv,
const char* method,
int argc = 0,
v8::Local<v8::Value>* argv = nullptr);
// Call with valid HandleScope and while inside Context scope.
v8::Local<v8::Value> MakeCallback(Environment* env,
v8::Local<v8::Object> recv,
v8::Local<v8::String> symbol,
int argc = 0,
v8::Local<v8::Value>* argv = nullptr);
// Call with valid HandleScope and while inside Context scope.
v8::Local<v8::Value> MakeCallback(Environment* env,
v8::Local<v8::Value> recv,
v8::Local<v8::Function> callback,
int argc = 0,
v8::Local<v8::Value>* argv = nullptr);
// Convert a struct sockaddr to a { address: '1.2.3.4', port: 1234 } JS object. // Convert a struct sockaddr to a { address: '1.2.3.4', port: 1234 } JS object.
// Sets address and port properties on the info object and returns it. // Sets address and port properties on the info object and returns it.
// If |info| is omitted, a new object is returned. // If |info| is omitted, a new object is returned.

Loading…
Cancel
Save