• Nodejs源码系列


    一直想着看Nodej源码,断断续续的折腾了一下,但总串不起来,太久不看又忘记。决心每天看一点,特地记录在这里,作为逼迫自己的动力。 

    2019/09/22 一、源码编译

    之前在电脑上了下源码,源码目录截图:

     编译通过了,编译命令:make -j4

    尝试修改下源码文件:lib/http.js,加入一行打印代码:

    之后,编译 make -j4,第一次编译会花点时间,之后编译会快很多。编译之后,在当前目录下生成out/Release目录。

    看看修改的代码是不是有效:

    cd out/Release
    ./node
    require('http')

    可以看到打印出了required http haha,修改成功。

    2019/09/23 二、node进程启动

    入口文件:src/node_main.cc,

     
     _WIN32 用来判断是否是windows平台。
      之后还有 __linux__、__POSIX__ 这样的宏,但都不属于mac上的宏,所以这部分可以先忽略。值得注意的是NODE_SHARED_MODE定义在node.gypi里,不太懂。(2019/09/28 增加)
     
    然后进入main函数 :
    设置标准输出、标准错误输出不带缓冲,立即输出到控制台:
      // Disable stdio buffering, it interacts poorly with printf()
      // calls elsewhere in the program (e.g., any logging from V8.)
      setvbuf(stdout, nullptr, _IONBF, 0);
      setvbuf(stderr, nullptr, _IONBF, 0);

    再调用了node::Start函数,传入参数。

    int main(int argc, char* argv[]) {
     ...

    return node::Start(argc, argv); }

     比如说使用 node /xxxx/test.js 执行时,argc是2,argv则是['/xxxx/node', '/xxxx/test.js'],第一个是node的执行路径。

    再来看node::Start函数在src/node.cc文件:

    int Start(int argc, char** argv) {
        atexit([] () { uv_tty_reset_mode(); }); // 注册退出时执行的函数
        
        PlatformInit(); // 平台初始化,在mac上好像可以略过
        performance::performance_node_start = PERFORMANCE_NOW(); // 简单理解为当前时间
        argv = uv_setup_args(argc, argv);//存储参数Store the program arguments. Required for uv_get_process_title/uv_set_process_title argv还是没变
      std::vector<std::string> args(argv, argv + argc);  // 创建argv的拷贝
      std::vector<std::string> exec_args;
      // This needs to run *before* V8::Initialize().
      Init(&args, &exec_args);
     ... v8_platform.Initialize( per_process_opts->v8_thread_pool_size); V8::Initialize(); performance::performance_v8_start = PERFORMANCE_NOW(); v8_initialized = true;
    const int exit_code = Start(uv_default_loop(), args, exec_args);
    v8_platform.StopTracingAgent(); v8_initialized
    = false; V8::Dispose(); v8_platform.Dispose(); return exit_code; }

    可以大概看出流程:

    一、Init函数初始化了些什么东西。

    Init函数挺有意思,

    void Init(std::vector<std::string>* argv,
              std::vector<std::string>* exec_argv) {
      // Initialize prog_start_time to get relative uptime.
      prog_start_time = static_cast<double>(uv_now(uv_default_loop()));
    
      // Register built-in modules
      RegisterBuiltinModules();
    其中的RegisterBuiltinModules定义如下:
    void RegisterBuiltinModules() {
    #define V(modname) _register_##modname();
      NODE_BUILTIN_MODULES(V)
    #undef V
    }

    只是调用了NODE_BUILTIN_MODULES,传入了一个宏定义。而 NODE_BUILTING_MODULES定义在node_internals.h头文件:

    #define NODE_BUILTIN_MODULES(V)                                               
      NODE_BUILTIN_STANDARD_MODULES(V)                                            
      NODE_BUILTIN_OPENSSL_MODULES(V)                                             
      NODE_BUILTIN_ICU_MODULES(V)

    NODE_BUILTIN_STANDARD_MODULES:
    #define NODE_BUILTIN_STANDARD_MODULES(V)                                      
        V(async_wrap)                                                             
        V(buffer)                                                                 
        V(cares_wrap)                                                             
        V(config)                                                                 
        V(contextify)                                                             
        V(domain)                                                                 
        V(fs)                                                                     
        V(fs_event_wrap)                                                          
        V(heap_utils)                                                             
        V(http2)                                                                  
        V(http_parser)                                                            
        V(inspector)                                                              
        V(js_stream)                                                              
        V(messaging)                                                              
        V(module_wrap)                                                            
        V(options)                                                                
        V(os)                                                                     
        V(performance)                                                            
        V(pipe_wrap)                                                              
        V(process_wrap)                                                           
        V(serdes)                                                                 
        V(signal_wrap)                                                            
        V(spawn_sync)                                                             
        V(stream_pipe)                                                            
        V(stream_wrap)                                                            
        V(string_decoder)                                                         
        V(symbols)                                                                
        V(tcp_wrap)                                                               
        V(timer_wrap)                                                             
        V(trace_events)                                                           
        V(tty_wrap)                                                               
        V(types)                                                                  
        V(udp_wrap)                                                               
        V(url)                                                                    
        V(util)                                                                   
        V(uv)                                                                     
        V(v8)                                                                     
        V(worker)                                                                 
        V(zlib)

    宏之间的互相调用,但是在node_internals.h里找不到async_wrap的定义,不知道在哪里定义的。(2019/09/28 增加)

    二、初始化v8引擎。

    三、调用Start函数,传入事件循环。具体看Start函数。

    Start函数还是在node.cc文件:

    inline int Start(uv_loop_t* event_loop,
                     const std::vector<std::string>& args,
                     const std::vector<std::string>& exec_args) {
     ...
    Isolate* const isolate = NewIsolate(allocator.get()); { Mutex::ScopedLock scoped_lock(node_isolate_mutex); CHECK_NULL(node_isolate); node_isolate = isolate; } int exit_code; {
      ...
    // 又调用了重载函数 exit_code = Start(isolate, isolate_data.get(), args, exec_args); }  ... isolate->Dispose(); return exit_code; }

    找到重载函数Start:

    inline int Start(Isolate* isolate, IsolateData* isolate_data,
                     const std::vector<std::string>& args,
                     const std::vector<std::string>& exec_args) {
      HandleScope handle_scope(isolate);
      Local<Context> context = NewContext(isolate);
      Context::Scope context_scope(context);
      Environment env(isolate_data, context, v8_platform.GetTracingAgentWriter());
      env.Start(args, exec_args, v8_is_profiling);
    
      const char* path = args.size() > 1 ? args[1].c_str() : nullptr;
      ...
      {
        Environment::AsyncCallbackScope callback_scope(&env);
        env.async_hooks()->push_async_ids(1, 0);
        LoadEnvironment(&env);
        env.async_hooks()->pop_async_id(1);
      }
    }

    继续LoadEnvironment函数。

    LoadEnvironment函数:

    void LoadEnvironment(Environment* env) {
      HandleScope handle_scope(env->isolate());
      ...
    // 读internal/bootstrap/loaders.js文件内容 Local<String> loaders_name = FIXED_ONE_BYTE_STRING(env->isolate(), "internal/bootstrap/loaders.js");

    // 包裹刚才读取的loaders.js内容 MaybeLocal
    <Function> loaders_bootstrapper = GetBootstrapper(env, LoadersBootstrapperSource(env), loaders_name);

     // 读取node.js文件内容 Local
    <String> node_name = FIXED_ONE_BYTE_STRING(env->isolate(), "internal/bootstrap/node.js");

    // 包裹node.js, MaybeLocal
    <Function> node_bootstrapper = GetBootstrapper(env, NodeBootstrapperSource(env), node_name); Local<Value> loaders_bootstrapper_args[] = { env->process_object(), get_binding_fn, get_linked_binding_fn, get_internal_binding_fn, Boolean::New(env->isolate(), env->options()->debug_options->break_node_first_line) }; // Bootstrap internal loaders Local<Value> bootstrapped_loaders;
    // 执行loaders.js,得到一个对象:{
    internalBinding, NativeModule }
    if (!ExecuteBootstrapper(env, loaders_bootstrapper.ToLocalChecked(),
                               arraysize(loaders_bootstrapper_args),
                               loaders_bootstrapper_args,
                               &bootstrapped_loaders)) {
        return;
      }
    
      // Bootstrap Node.js
      Local<Object> bootstrapper = Object::New(env->isolate());
      SetupBootstrapObject(env, bootstrapper);
      Local<Value> bootstrapped_node;
      Local<Value> node_bootstrapper_args[] = {
        env->process_object(),
        bootstrapper,
        bootstrapped_loaders
      };
    // node.js是一系列的函数调用,设置node进程全局变量,如设置process对象属性值
    if (!ExecuteBootstrapper(env, node_bootstrapper.ToLocalChecked(), arraysize(node_bootstrapper_args), node_bootstrapper_args, &bootstrapped_node)) { return; } }

    之后,就是进入事件循环。

  • 相关阅读:
    【NLP_Stanford课堂】最小编辑距离
    【NLP_Stanford课堂】句子切分
    【NLP_Stanford课堂】词形规范化
    【NLP_Stanford课堂】分词
    【NLP_Stanford课堂】正则表达式
    【Python自然语言处理】第一章学习笔记——搜索文本、计数统计和字符串链表
    【C++ Primer】详解C++和C中的float中的有效数字
    【C++ Primer】读书笔记_第一章
    【SQL Server 2012】按倒序存储“分组统计”结果的临时表到新建表
    Git学习
  • 原文地址:https://www.cnblogs.com/cool-fire/p/11570039.html
Copyright © 2020-2023  润新知