From e0c194b8e73ddea75449d850d17b6723721561b8 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 21 May 2017 17:05:40 +0200 Subject: [PATCH] re-untangle domain/async_hooks promise support --- src/async-wrap.cc | 84 ++++++++++++++++++++++++++++------------------- src/async-wrap.h | 3 ++ src/node.cc | 26 +++++++++++++++ 3 files changed, 80 insertions(+), 33 deletions(-) diff --git a/src/async-wrap.cc b/src/async-wrap.cc index e6c33d594cfeae..dcef462b8e9483 100644 --- a/src/async-wrap.cc +++ b/src/async-wrap.cc @@ -179,23 +179,50 @@ static void PushBackDestroyId(Environment* env, double id) { } -static bool PreCallbackExecution(AsyncWrap* wrap) { - AsyncHooks* async_hooks = wrap->env()->async_hooks(); - if (wrap->env()->using_domains()) { - Local domain_v = wrap->object()->Get(wrap->env()->domain_string()); - if (domain_v->IsObject()) { - Local domain = domain_v.As(); - if (domain->Get(wrap->env()->disposed_string())->IsTrue()) - return false; - Local enter_v = domain->Get(wrap->env()->enter_string()); - if (enter_v->IsFunction()) { - if (enter_v.As()->Call(domain, 0, nullptr).IsEmpty()) { - FatalError("node::AsyncWrap::MakeCallback", - "domain enter callback threw, please report this"); - } +bool DomainEnter(Environment* env, Local object) { + Local domain_v = object->Get(env->domain_string()); + if (domain_v->IsObject()) { + Local domain = domain_v.As(); + if (domain->Get(env->disposed_string())->IsTrue()) + return true; + Local enter_v = domain->Get(env->enter_string()); + if (enter_v->IsFunction()) { + if (enter_v.As()->Call(domain, 0, nullptr).IsEmpty()) { + FatalError("node::AsyncWrap::MakeCallback", + "domain enter callback threw, please report this"); } } } + return false; +} + + +bool DomainExit(Environment* env, v8::Local object) { + Local domain_v = object->Get(env->domain_string()); + if (domain_v->IsObject()) { + Local domain = domain_v.As(); + if (domain->Get(env->disposed_string())->IsTrue()) + return true; + Local exit_v = domain->Get(env->exit_string()); + if (exit_v->IsFunction()) { + if (exit_v.As()->Call(domain, 0, nullptr).IsEmpty()) { + FatalError("node::AsyncWrap::MakeCallback", + "domain exit callback threw, please report this"); + } + } + } + return false; +} + + +static bool PreCallbackExecution(AsyncWrap* wrap, bool run_domain_cbs) { + AsyncHooks* async_hooks = wrap->env()->async_hooks(); + + if (wrap->env()->using_domains() && run_domain_cbs) { + bool is_disposed = DomainEnter(wrap->env(), wrap->object()); + if (is_disposed) + return false; + } if (async_hooks->fields()[AsyncHooks::kBefore] > 0) { Local uid = Number::New(wrap->env()->isolate(), wrap->get_id()); @@ -209,11 +236,12 @@ static bool PreCallbackExecution(AsyncWrap* wrap) { return false; } } + return true; } -static bool PostCallbackExecution(AsyncWrap* wrap) { +static bool PostCallbackExecution(AsyncWrap* wrap, bool run_domain_cbs) { AsyncHooks* async_hooks = wrap->env()->async_hooks(); // If the callback failed then the after() hooks will be called at the end @@ -231,20 +259,10 @@ static bool PostCallbackExecution(AsyncWrap* wrap) { } } - if (wrap->env()->using_domains()) { - Local domain_v = wrap->object()->Get(wrap->env()->domain_string()); - if (domain_v->IsObject()) { - Local domain = domain_v.As(); - if (domain->Get(wrap->env()->disposed_string())->IsTrue()) - return false; - Local exit_v = domain->Get(wrap->env()->exit_string()); - if (exit_v->IsFunction()) { - if (exit_v.As()->Call(domain, 0, nullptr).IsEmpty()) { - FatalError("node::AsyncWrap::MakeCallback", - "domain exit callback threw, please report this"); - } - } - } + if (wrap->env()->using_domains() && run_domain_cbs) { + bool is_disposed = DomainExit(wrap->env(), wrap->object()); + if (is_disposed) + return false; } return true; @@ -301,9 +319,9 @@ static void PromiseHook(PromiseHookType type, Local promise, static_cast(external_wrap.As()->Value()); CHECK_NE(wrap, nullptr); if (type == PromiseHookType::kBefore) { - PreCallbackExecution(wrap); + PreCallbackExecution(wrap, false); } else if (type == PromiseHookType::kAfter) { - PostCallbackExecution(wrap); + PostCallbackExecution(wrap, false); } } @@ -554,7 +572,7 @@ Local AsyncWrap::MakeCallback(const Local cb, get_id(), get_trigger_id()); - if (!PreCallbackExecution(this)) { + if (!PreCallbackExecution(this, true)) { return Local(); } @@ -566,7 +584,7 @@ Local AsyncWrap::MakeCallback(const Local cb, return Local(); } - if (!PostCallbackExecution(this)) { + if (!PostCallbackExecution(this, true)) { return Local(); } diff --git a/src/async-wrap.h b/src/async-wrap.h index 0d1bdd9b92ab9f..0ce837d5c3f891 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -124,6 +124,9 @@ class AsyncWrap : public BaseObject { void LoadAsyncWrapperInfo(Environment* env); +bool DomainEnter(Environment* env, v8::Local object); +bool DomainExit(Environment* env, v8::Local object); + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/node.cc b/src/node.cc index f50cc817d5c0ae..7319bf257697b8 100644 --- a/src/node.cc +++ b/src/node.cc @@ -143,6 +143,7 @@ using v8::Number; using v8::Object; using v8::ObjectTemplate; using v8::Promise; +using v8::PromiseHookType; using v8::PromiseRejectMessage; using v8::PropertyCallbackInfo; using v8::ScriptOrigin; @@ -1116,6 +1117,29 @@ bool ShouldAbortOnUncaughtException(Isolate* isolate) { } +void DomainPromiseHook(PromiseHookType type, + Local promise, + Local parent, + void* arg) { + Environment* env = static_cast(arg); + Local context = env->context(); + + if (type == PromiseHookType::kInit && env->in_domain()) { + promise->Set(context, + env->domain_string(), + env->domain_array()->Get(context, + 0).ToLocalChecked()).FromJust(); + return; + } + + if (type == PromiseHookType::kBefore) { + DomainEnter(env, promise); + } else if (type == PromiseHookType::kAfter) { + DomainExit(env, promise); + } +} + + void SetupDomainUse(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -1155,6 +1179,8 @@ void SetupDomainUse(const FunctionCallbackInfo& args) { Local array_buffer = ArrayBuffer::New(env->isolate(), fields, sizeof(*fields) * fields_count); + env->AddPromiseHook(DomainPromiseHook, static_cast(env)); + args.GetReturnValue().Set(Uint32Array::New(array_buffer, 0, fields_count)); }