読者です 読者をやめる 読者になる 読者になる

node.ccでのDomain対応

https://github.com/joyent/node/blob/master/src/node.cc ですね。ここには来たくなかったのですが、実はキレイなコードで読みやすかったw。

Handle<Value> MakeDomainCallback(Environment* env, const Handle<Object> object,
        const Handle<Function> callback, int argc, Handle<Value> argv[]) {
// (省略)
    domain = domain_v.As<Object>();
    if (domain->Get(env->disposed_string())->IsTrue()) {
      // domain has been disposed of. 
      return Undefined(node_isolate);
    }
    Local<Function> enter = domain->Get(env->enter_string()).As<Function>();
    assert(enter->IsFunction());
    enter->Call(domain, 0, NULL); // ここでDomain#enter()している!
// (省略)
    Local<Value> ret = callback->Call(object, argc, argv); // ここでコールバック実行!いけ!
    if (try_catch.HasCaught()) {
        return Undefined(node_isolate); // 例外発生!
    }
// (省略)
    Local<Function> exit = domain->Get(env->exit_string()).As<Function>();
    assert(exit->IsFunction());
    exit->Call(domain, 0, NULL);  // ここでDomain#exit()している!
// (省略)
}

V8の操作なんでC++ですが、やってることはDomain#enter()とDomain#exit()ではさんでコールバック関数を実行するというそのままです。例外が出たらその場でリターン。
このMakeDomainCallbackはMakeCallbackから呼ばれ、そのMakeCallbackを呼ぶのは以下。

  • CheckImmediate
    • NeedImmediateCallbackSetter
      • SetupProcessObject
        • CreateEnvironment
          • Start
  • EmitDebugEnabledAsyncCallback
    • Init
      • Start
  • EmitExit
    • Start

全部、ルートはStartに収斂しました。MakeCallbackがnode.hでEXTERNしてるので別系のコールスタックのどこかで呼んでる可能性もあるのでしょうが、まずはOKじゃないかな。ドメインについては、ほぼわかったと思う。enter()とexit()は自分でやっちゃダメですよと。スケジュールされたコールバック実行でもenter()とexit()を自動でやってくれているからこれを触るとDomainスタックを操作しちゃうことになる。