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