#include "async-wrap.h" #include "async-wrap-inl.h" #include "env.h" #include "env-inl.h" #include "util.h" #include "util-inl.h" #include "v8.h" using v8::Array; using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::Handle; using v8::HandleScope; using v8::Integer; using v8::Isolate; using v8::Local; using v8::Object; using v8::TryCatch; using v8::Value; using v8::kExternalUint32Array; namespace node { static void EnableHooksJS(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); env->async_hooks()->set_enable_callbacks(1); } static void DisableHooksJS(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); env->async_hooks()->set_enable_callbacks(0); } static void SetupHooks(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); CHECK(args[0]->IsFunction()); CHECK(args[1]->IsFunction()); CHECK(args[2]->IsFunction()); env->set_async_hooks_init_function(args[0].As()); env->set_async_hooks_pre_function(args[1].As()); env->set_async_hooks_post_function(args[2].As()); env->set_using_asyncwrap(true); } static void Initialize(Handle target, Handle unused, Handle context) { Environment* env = Environment::GetCurrent(context); Isolate* isolate = env->isolate(); HandleScope scope(isolate); env->SetMethod(target, "setupHooks", SetupHooks); env->SetMethod(target, "disable", DisableHooksJS); env->SetMethod(target, "enable", EnableHooksJS); Local async_providers = Object::New(isolate); #define V(PROVIDER) \ async_providers->Set(FIXED_ONE_BYTE_STRING(isolate, #PROVIDER), \ Integer::New(isolate, AsyncWrap::PROVIDER_ ## PROVIDER)); NODE_ASYNC_PROVIDER_TYPES(V) #undef V target->Set(FIXED_ONE_BYTE_STRING(isolate, "Providers"), async_providers); } Handle AsyncWrap::MakeCallback(const Handle cb, int argc, Handle* argv) { CHECK(env()->context() == env()->isolate()->GetCurrentContext()); Local context = object(); Local process = env()->process_object(); Local domain; bool has_domain = false; bool has_abort_on_uncaught_and_domains = false; if (env()->using_domains()) { Local domain_v = context->Get(env()->domain_string()); has_domain = domain_v->IsObject(); if (has_domain) { domain = domain_v.As(); if (domain->Get(env()->disposed_string())->IsTrue()) return Undefined(env()->isolate()); has_abort_on_uncaught_and_domains = env()->using_abort_on_uncaught_exc(); } } TryCatch try_catch; try_catch.SetVerbose(true); if (has_domain) { Local enter_v = domain->Get(env()->enter_string()); if (enter_v->IsFunction()) { enter_v.As()->Call(domain, 0, nullptr); if (try_catch.HasCaught()) return Undefined(env()->isolate()); } } if (has_async_queue()) { try_catch.SetVerbose(false); env()->async_hooks_pre_function()->Call(context, 0, nullptr); if (try_catch.HasCaught()) FatalError("node::AsyncWrap::MakeCallback", "pre hook threw"); try_catch.SetVerbose(true); } Local ret; if (has_abort_on_uncaught_and_domains) { Local fn = process->Get(env()->domain_abort_uncaught_exc_string()); if (fn->IsFunction()) { Local special_context = Array::New(env()->isolate(), 2); special_context->Set(0, context); special_context->Set(1, cb); ret = fn.As()->Call(special_context, argc, argv); } else { ret = cb->Call(context, argc, argv); } } else { ret = cb->Call(context, argc, argv); } if (try_catch.HasCaught()) { return Undefined(env()->isolate()); } if (has_async_queue()) { try_catch.SetVerbose(false); env()->async_hooks_post_function()->Call(context, 0, nullptr); if (try_catch.HasCaught()) FatalError("node::AsyncWrap::MakeCallback", "post hook threw"); try_catch.SetVerbose(true); } if (has_domain) { Local exit_v = domain->Get(env()->exit_string()); if (exit_v->IsFunction()) { exit_v.As()->Call(domain, 0, nullptr); if (try_catch.HasCaught()) return Undefined(env()->isolate()); } } Environment::TickInfo* tick_info = env()->tick_info(); if (tick_info->in_tick()) { return ret; } if (tick_info->length() == 0) { env()->isolate()->RunMicrotasks(); } if (tick_info->length() == 0) { tick_info->set_index(0); return ret; } tick_info->set_in_tick(true); env()->tick_callback_function()->Call(process, 0, nullptr); tick_info->set_in_tick(false); if (try_catch.HasCaught()) { tick_info->set_last_threw(true); return Undefined(env()->isolate()); } return ret; } } // namespace node NODE_MODULE_CONTEXT_AWARE_BUILTIN(async_wrap, node::Initialize)