nodejsモジュールロード分析(1)
6394 ワード
前言
上編のnodejs起動フローの分析には、いくつかの問題が残されています.この記事は主にモジュールロードの流れを説明します.皆さんはtimerモジュールの関連機能を熟知すべきです.私たちはtimerをきっかけにして、一歩ずつ見ていきましょう.
C++init方法開始
下記の関数は全部src/node.ccにあります.
最後の言葉
分析中、多くのマクロ処理があります.マクロを一つずつ展開して、紙に書いて分析します.さもなくば一目でとてもみっともないのは全体の姿を点検します.
本稿を通じて、Register Modulesとどのようにモジュールを初期化するかについて大まかな理解が必要である.でも、GetInternal Bindingという方法は誰が呼び出したのか、今度は分析します.
上編のnodejs起動フローの分析には、いくつかの問題が残されています.この記事は主にモジュールロードの流れを説明します.皆さんはtimerモジュールの関連機能を熟知すべきです.私たちはtimerをきっかけにして、一歩ずつ見ていきましょう.
C++init方法開始
下記の関数は全部src/node.ccにあります.
void Init(std::vector<:string>* argv,
std::vector<:string>* exec_argv) {
...
// 。
RegisterBuiltinModules();
...
}
一見して、このレジスターBultin Modules方法が鍵となります.彼は何ですか?void RegisterBuiltinModules() {
#define V(modname) _register_##modname();
NODE_BUILTIN_MODULES(V)
#undef V
}
もともとは方法ではなく、マクロ定義です.じゃ、私達はNODE_を見てみます.BUILTIN_MODULESこれはなんですか?下記の書類はsrc/node_にあります.internals.hにおいて:#define NODE_BUILTIN_MODULES(V) \
NODE_BUILTIN_STANDARD_MODULES(V) \
NODE_BUILTIN_OPENSSL_MODULES(V) \
NODE_BUILTIN_ICU_MODULES(V)
お利口さん、またマクロです.まるでマクロの地獄です.我慢して、また下を見てみましょう.#define NODE_BUILTIN_STANDARD_MODULES(V) \
V(async_wrap) \
...
V(timer) \
他の2つのマクロは似ていますので、載せません.このマクロの中には、探したいタイマーがいるようです.この三つのマクロを合成してみましょう.何かを見てみましょう._register_timer();
他の類似点については、これ以上説明しない.このマクロは順番に呼び出されました.レジスターxxの方法.C++マクロの中に、奄菗は文字列接続を表します.〹〹の前の文字列で〹をつづり合わせた後の文字列に相当します.これを見つけました.レジスターtimerの方法が鍵です.全文検索しますレジスターtimer()メソッドは、見つけられないことに気づきました.レジスターというキーワードを検索してみたら、次のようなマクロが見つかります.internals.hにおいて:#define NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \
static node::node_module _module = { \
NODE_MODULE_VERSION, /* */ \
flags, /* ,builtin,internal,linked*/ \
nullptr, /*nm_dso_handle. */ \
__FILE__, /* */ \
nullptr, /* */ \
(node::addon_context_register_func) (regfunc), /* */ \
NODE_STRINGIFY(modname), /* */ \
priv, /* */ \
nullptr /* node_module */ \
}; \
void _register_ ## modname() { \
node_module_register(&_module); \
}
見ることができます.このマクロは構造体、node_を定義しています.moduleはsrc/node.hで定義されています.このマクロはモジュール名、登録方法、プライベートポインタ、モジュールタイプを転送します.そして一つの方法を定義しました.私たちが探しているのです.レギター.modnameメソッド.その中でまたmode_を呼び出しました.module_レジスターの方法.ここではまず実現を急ぐのではなく、誰がこのマクロを呼び出したのかを先に見に行きます.検索したら、ファイルのsrc/node_にあります.internals.hには、このようなマクロがある.#define NODE_MODULE_CONTEXT_AWARE_INTERNAL(modname, regfunc) \
NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, nullptr, NM_F_INTERNAL)
NODE_MODULE_CONTEXT_AWARE_INTERNALというマクロは、上のマクロを呼び出し、モジュール名、登録方法を転送し、プライベート変数null、モジュールタイプを内蔵モジュールタイプに転送します.次に誰がNODE_を呼んだかを確認します.MODULE_CONTEXT_AWARE_INTERNAL.検索は多くの場所で呼び出すことができます.私たちは関心のあるSrc/timers.ccファイルを見つけました.void Initialize(Local
モジュール名パラメータはtimersであり,初期化方法のパラメータ伝達はInitialize法であることがわかる.ここまではコールの元が見つかりました.じゃ私達は引き続きnode_を見ます.module_レジスターの方法は何をしましたか?この方法はsrc/node.ccにあります.extern "C" void node_module_register(void* m) {
struct node_module* mp = reinterpret_cast(m);
...
else if (mp->nm_flags & NM_F_INTERNAL) {
mp->nm_link = modlist_internal;
modlist_internal = mp;
}
...
}
ここではすべてのモジュールを順次リンクしてチェーンを作っているだけです.コールがないですか?初期化していませんか?ここでは変数modlist_に注意してください.インターナショナルは後から使います.ここにGetInternal Bindingがあります.彼はglobalオブジェクトにバインドされ、jsに呼び出されます.この方法はjsのソースコードを結合しなければ出典が分かりません.この方法はsrc/node.ccにあります.static void GetInternalBinding(const FunctionCallbackInfo& args) {
...// 。
Local module = args[0].As();
...// 。
node_module* mod = get_internal_module(*module_v);
if (mod != nullptr) {
// 。
exports = InitModule(env, mod, module);
}
...
}
get_を見せてくださいbuilting.module方法は、この方法はsrc/node.ccにあります.node_module* get_internal_module(const char* name) {
return FindModule(modlist_internal, name, NM_F_INTERNAL);
}
inline struct node_module* FindModule(struct node_module* list,
const char* name,
int flag) {
struct node_module* mp;
for (mp = list; mp != nullptr; mp = mp->nm_link) {
if (strcmp(mp->nm_modname, name) == 0)
break;
}
...
return mp;
}
メソッド内部でFindModuleメソッドを呼び出しました.最初のパラメータは分かりますか?modlist_インターナショナル上のRegister Buiilting Modules方式で生成されたモジュールです.具体的な検索過程も比較的簡単で、このチェーンを遍歴して、モジュール名を比較して、同じかどうか、そしてモジュールを入手します.InitModuleの方法を引き続き見てください.同じsrc/node.ccにあります.static Local
上のtimer.ccのInitializeメソッドを思い出してみます.ここが呼び出された場所です.これでモジュールはプログラムにロードされます.最後の言葉
分析中、多くのマクロ処理があります.マクロを一つずつ展開して、紙に書いて分析します.さもなくば一目でとてもみっともないのは全体の姿を点検します.
本稿を通じて、Register Modulesとどのようにモジュールを初期化するかについて大まかな理解が必要である.でも、GetInternal Bindingという方法は誰が呼び出したのか、今度は分析します.