current commit
261014.1 · src: keep ALS store in AsyncResource::MakeCallback
#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)