async_wrap: call callback in destructor
authorTrevor Norris <trev.norris@gmail.com>
Tue, 20 Oct 2015 18:20:10 +0000 (12:20 -0600)
committerMyles Borins <mborins@us.ibm.com>
Tue, 19 Jan 2016 19:52:12 +0000 (11:52 -0800)
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>
src/async-wrap-inl.h
src/async-wrap.cc
src/async-wrap.h
src/env.h
test/parallel/test-async-wrap-disabled-propagate-parent.js
test/parallel/test-async-wrap-propagate-parent.js

index 9aaf67d..1d9ebe2 100644 (file)
@@ -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);
 }
index 767e768..c9f5caa 100644 (file)
@@ -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>());
 }
 
 
index 5fbd230..5db2960 100644 (file)
@@ -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;
 
index e41863a..ea5e8fe 100644 (file)
--- a/src/env.h
+++ b/src/env.h
@@ -231,6 +231,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)                                      \
index de36071..70d82be 100644 (file)
@@ -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.
index 8074b00..beeb27b 100644 (file)
@@ -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.