mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 18:25:13 +08:00
AsyncResource saves the async context frame when it is created, and MakeCallback() enters it with async_context_frame::Scope. Then node::MakeCallback() opens the callback scope with an undefined frame, so the callback never runs in the saved one. Since AsyncContextFrame is the default, AsyncLocalStorage loses its store in these callbacks. Pass the saved frame to InternalMakeCallback(), as the Node-API AsyncContext already does. This also removes the Scope from every call, with its two Environment lookups and its global handle. Refs: https://github.com/nodejs/node/pull/66316 Refs: https://github.com/nodejs/node/issues/43038 Refs: https://github.com/nodejs/performance/issues/24 Signed-off-by: Nigro Simone <nigro.simone@gmail.com> PR-URL: https://github.com/nodejs/node/pull/66326 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
82 lines
2.5 KiB
C++
82 lines
2.5 KiB
C++
#include <node.h>
|
|
#include <uv.h>
|
|
#include <v8.h>
|
|
|
|
using v8::Context;
|
|
using v8::Function;
|
|
using v8::FunctionCallbackInfo;
|
|
using v8::Global;
|
|
using v8::HandleScope;
|
|
using v8::Isolate;
|
|
using v8::Local;
|
|
using v8::Object;
|
|
using v8::Value;
|
|
|
|
// Same order as the types in index.js.
|
|
enum Type { kMakeCallback, kAsyncResource, kCall };
|
|
|
|
struct State {
|
|
uv_timer_t timer;
|
|
Isolate* isolate;
|
|
int64_t n;
|
|
Type type;
|
|
Global<Function> fn;
|
|
Global<Function> done;
|
|
node::AsyncResource* resource = nullptr;
|
|
|
|
~State() { delete resource; }
|
|
};
|
|
|
|
static void OnTimer(uv_timer_t* handle) {
|
|
State* state = static_cast<State*>(handle->data);
|
|
Isolate* isolate = state->isolate;
|
|
HandleScope handle_scope(isolate);
|
|
Local<Function> fn = state->fn.Get(isolate);
|
|
Local<Context> context = fn->GetCreationContextChecked(isolate);
|
|
Context::Scope context_scope(context);
|
|
Local<Object> recv = context->Global();
|
|
for (int64_t i = 0; i < state->n; i++) {
|
|
HandleScope inner_scope(isolate);
|
|
switch (state->type) {
|
|
case kMakeCallback:
|
|
(void)node::MakeCallback(isolate, recv, fn, 0, nullptr, {0, 0});
|
|
break;
|
|
case kAsyncResource:
|
|
(void)state->resource->MakeCallback(fn, 0, nullptr);
|
|
break;
|
|
case kCall:
|
|
(void)fn->Call(context, recv, 0, nullptr);
|
|
break;
|
|
}
|
|
}
|
|
Local<Function> done = state->done.Get(isolate);
|
|
(void)node::MakeCallback(isolate, recv, done, 0, nullptr, {0, 0});
|
|
uv_close(reinterpret_cast<uv_handle_t*>(&state->timer),
|
|
[](uv_handle_t* h) { delete static_cast<State*>(h->data); });
|
|
}
|
|
|
|
// run(n, fn, done, type): calls fn n times from a timer, then calls done.
|
|
static void Run(const FunctionCallbackInfo<Value>& args) {
|
|
Isolate* isolate = args.GetIsolate();
|
|
State* state = new State;
|
|
state->isolate = isolate;
|
|
state->n = args[0]->IntegerValue(isolate->GetCurrentContext()).FromJust();
|
|
state->fn.Reset(isolate, args[1].As<Function>());
|
|
state->done.Reset(isolate, args[2].As<Function>());
|
|
state->type = static_cast<Type>(
|
|
args[3]->Int32Value(isolate->GetCurrentContext()).FromJust());
|
|
if (state->type == kAsyncResource) {
|
|
state->resource =
|
|
new node::AsyncResource(isolate, Object::New(isolate), "Benchmark");
|
|
}
|
|
state->timer.data = state;
|
|
uv_timer_init(node::GetCurrentEventLoop(isolate), &state->timer);
|
|
uv_timer_start(&state->timer, OnTimer, 0, 0);
|
|
}
|
|
|
|
static void Initialize(Local<Object> target, Local<Value> module, void* data) {
|
|
NODE_SET_METHOD(target, "run", Run);
|
|
}
|
|
|
|
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
|