Browse Source

async_wrap: call callback in destructor

Call a user's callback to notify that the handle has been destroyed.
Only pass the id of the AsyncWrap instance since the object no longer
exists.

The object that's being destructed should never be inspected within the
callback or any time afterward.

This commit make a breaking change. The init callback will now be passed
arguments in the order of provider, id, parent.

PR-URL: https://github.com/nodejs/node/pull/3461
Reviewed-By: Fedor Indutny <fedor@indutny.com>
v5.x
Trevor Norris 9 years ago
committed by Rod Vagg
parent
commit
b663d2bbb5
  1. 19
      src/async-wrap-inl.h
  2. 3
      src/async-wrap.cc
  3. 2
      src/async-wrap.h
  4. 1
      src/env.h
  5. 2
      test/parallel/test-async-wrap-disabled-propagate-parent.js
  6. 2
      test/parallel/test-async-wrap-propagate-parent.js

19
src/async-wrap-inl.h

@ -41,11 +41,12 @@ inline AsyncWrap::AsyncWrap(Environment* env,
v8::Local<v8::Value> argv[] = {
v8::Int32::New(env->isolate(), provider),
v8::Integer::New(env->isolate(), get_uid()),
Null(env->isolate())
};
if (parent != nullptr)
argv[1] = parent->object();
argv[2] = parent->object();
v8::MaybeLocal<v8::Value> ret =
init_fn->Call(env->context(), object, ARRAY_SIZE(argv), argv);
@ -57,6 +58,22 @@ inline AsyncWrap::AsyncWrap(Environment* env,
}
inline AsyncWrap::~AsyncWrap() {
if (!ran_init_callback())
return;
v8::Local<v8::Function> fn = env()->async_hooks_destroy_function();
if (!fn.IsEmpty()) {
v8::HandleScope scope(env()->isolate());
v8::Local<v8::Value> uid = v8::Integer::New(env()->isolate(), get_uid());
v8::MaybeLocal<v8::Value> ret =
fn->Call(env()->context(), v8::Null(env()->isolate()), 1, &uid);
if (ret.IsEmpty())
FatalError("node::AsyncWrap::~AsyncWrap", "destroy hook threw");
}
}
inline bool AsyncWrap::ran_init_callback() const {
return static_cast<bool>(bits_ & 1);
}

3
src/async-wrap.cc

@ -131,6 +131,8 @@ static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
env->set_async_hooks_pre_function(args[1].As<Function>());
if (args[2]->IsFunction())
env->set_async_hooks_post_function(args[2].As<Function>());
if (args[3]->IsFunction())
env->set_async_hooks_destroy_function(args[3].As<Function>());
}
@ -156,6 +158,7 @@ static void Initialize(Local<Object> target,
env->set_async_hooks_init_function(Local<Function>());
env->set_async_hooks_pre_function(Local<Function>());
env->set_async_hooks_post_function(Local<Function>());
env->set_async_hooks_destroy_function(Local<Function>());
}

2
src/async-wrap.h

@ -51,7 +51,7 @@ class AsyncWrap : public BaseObject {
ProviderType provider,
AsyncWrap* parent = nullptr);
inline virtual ~AsyncWrap() override = default;
inline virtual ~AsyncWrap();
inline ProviderType provider_type() const;

1
src/env.h

@ -236,6 +236,7 @@ namespace node {
V(async_hooks_init_function, v8::Function) \
V(async_hooks_pre_function, v8::Function) \
V(async_hooks_post_function, v8::Function) \
V(async_hooks_destroy_function, v8::Function) \
V(binding_cache_object, v8::Object) \
V(buffer_constructor_function, v8::Function) \
V(buffer_prototype_object, v8::Object) \

2
test/parallel/test-async-wrap-disabled-propagate-parent.js

@ -10,7 +10,7 @@ let cntr = 0;
let server;
let client;
function init(type, parent) {
function init(type, id, parent) {
if (parent) {
cntr++;
// Cannot assert in init callback or will abort.

2
test/parallel/test-async-wrap-propagate-parent.js

@ -9,7 +9,7 @@ let cntr = 0;
let server;
let client;
function init(type, parent) {
function init(type, id, parent) {
if (parent) {
cntr++;
// Cannot assert in init callback or will abort.

Loading…
Cancel
Save