[Day 22] Node Event loop 1

前言

昨天, 我们知道了 JS 层藉由 V8 引用 C++ 层, C++ 层又利用 AIO (非同步IO) 注册事件, 接着我们就来看看负责处理事件的 libuv 在做甚麽吧。

Event loop 的启动

https://github.com/nodejs/node/blob/master/src/node_main.cc

来到 C++ 层的运行起点

int main(int argc, char* argv[]) {
#if defined(__POSIX__) && defined(NODE_SHARED_MODE)
  // In node::PlatformInit(), we squash all signal handlers for non-shared lib
  // build. In order to run test cases against shared lib build, we also need
  // to do the same thing for shared lib build here, but only for SIGPIPE for
  // now. If node::PlatformInit() is moved to here, then this section could be
  // removed.
  {
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &act, nullptr);
  }
#endif

#if defined(__linux__)
  node::per_process::linux_at_secure = getauxval(AT_SECURE);
#endif
  // 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);
  return node::Start(argc, argv);
}

重点其实就是最後的 node::Start(argc, argv);

int Start(int argc, char** argv) {
  InitializationResult result = InitializeOncePerProcess(argc, argv);
  if (result.early_return) {
    return result.exit_code;
  }

  {
    Isolate::CreateParams params;
    const std::vector<size_t>* indices = nullptr;
    const EnvSerializeInfo* env_info = nullptr;
    bool use_node_snapshot =
        per_process::cli_options->per_isolate->node_snapshot;
    if (use_node_snapshot) {
      v8::StartupData* blob = NodeMainInstance::GetEmbeddedSnapshotBlob();
      if (blob != nullptr) {
        params.snapshot_blob = blob;
        indices = NodeMainInstance::GetIsolateDataIndices();
        env_info = NodeMainInstance::GetEnvSerializeInfo();
      }
    }
    uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME);

    NodeMainInstance main_instance(&params,
                                   uv_default_loop(),
                                   per_process::v8_platform.Platform(),
                                   result.args,
                                   result.exec_args,
                                   indices);
    result.exit_code = main_instance.Run(env_info);
  }

  TearDownOncePerProcess();
  return result.exit_code;
}

可以看到实体化了一个 NodeMainInstance , 接着调用了该物件的 Run

void NodeMainInstance::Run(int* exit_code, Environment* env) {
  if (*exit_code == 0) {
    LoadEnvironment(env, StartExecutionCallback{});

    *exit_code = SpinEventLoop(env).FromMaybe(1);
  }

  ResetStdio();

  // TODO(addaleax): Neither NODE_SHARED_MODE nor HAVE_INSPECTOR really
  // make sense here.
#if HAVE_INSPECTOR && defined(__POSIX__) && !defined(NODE_SHARED_MODE)
  struct sigaction act;
  memset(&act, 0, sizeof(act));
  for (unsigned nr = 1; nr < kMaxSignal; nr += 1) {
    if (nr == SIGKILL || nr == SIGSTOP || nr == SIGPROF)
      continue;
    act.sa_handler = (nr == SIGPIPE) ? SIG_IGN : SIG_DFL;
    CHECK_EQ(0, sigaction(nr, &act, nullptr));
  }
#endif

#if defined(LEAK_SANITIZER)
  __lsan_do_leak_check();
#endif
}

找到 SpinEventLoop 这就是 Event loop (libuv) 的创建入口

补充 : LoadEnvironment(env, StartExecutionCallback{}); 这聚会往上创建 JS 层, 但基於主体, 不深入细讲。

所以可以视为, 这个函数里面的两句, 分别往上建立 JS 层, 和往下建立 libuv 层

// Runs the main loop for a given Environment. This roughly performs the
// following steps:
// 1. Call uv_run() on the event loop until it is drained.
// 2. Call platform->DrainTasks() on the associated platform/isolate.
//   3. If the event loop is alive again, go to Step 1.
// 4. Call EmitProcessBeforeExit().
//   5. If the event loop is alive again, go to Step 1.
// 6. Call EmitProcessExit() and forward the return value.
// If at any point node::Stop() is called, the function will attempt to return
// as soon as possible, returning an empty `Maybe`.
// This function only works if `env` has an associated `MultiIsolatePlatform`.
NODE_EXTERN v8::Maybe<int> SpinEventLoop(Environment* env);

查看注解可以得知其会运行 uv_run() method , 而这就是 libuv 的核心循环。

而这句函式, 就是从 C++ 层走入 libuv 的入口。

明天进度

今天从 C++ 层调用了外部方法准备运行 uv_run() , 这据说是 libuv 的核心循环, 明天一起来看看吧 !

明天见 !


<<:  a连结标签基础方法

>>:  Day10 Collectionview小实作4

ISO 27001 资讯安全管理系统 【解析】(七)

(五)员工 我们目前拥有多名员工,分别是管理阶层、软件开发、硬体维护、营业部门、客户管理及财务和管理...

32.Module2

在有namespace的module内访问全域内容(Global Assets): 如果你希望使用全...

个人or团队这回事(上)

讲到团队(Team),就会先讲到团体(Group)这个字,谈团队之前,其实要先这样想:根本没有团队这...

Day6:class函数

半夜睡不着来更新XD Python属於「物件导向程序语言」(Object-oriented prog...

Day 15 JavaScript NodeList vs HTMLCollection

NodeList 与 HTMLCollection 的主要差异点是节点的类型不一样: NodeLi...