// includes/uv.h
// 源码 302行
// 这里声明了uv_run函数.注释给的很清楚,这个函数的功能是启动事件循环,同时有三种不同启动模式可供选择:
UV_RUN_DEFAULT: 默认的循环模式,将会不断重复这个循环,直到"循环引用计数器(ref)"减为0.
UV_RUN_ONCE: 在没有待处理事件时uv_run将会阻塞,但这个事件循环仅仅轮询一次新触发的事件.当没有活跃的监听器或请求,函数返回0,否则返回非0值,表示还有更多待处理事件.
UV_RUN_NOWAIT: 即使没有待处理事件也不会阻塞uv_run函数,其余和UV_RUN_ONCE相同.
/*
* This function runs the event loop. It will act differently depending on the
* specified mode:
* - UV_RUN_DEFAULT: Runs the event loop until the reference count drops to
* zero. Always returns zero.
* - UV_RUN_ONCE: Poll for new events once. Note that this function blocks if
* there are no pending events. Returns zero when done (no active handles
* or requests left), or non-zero if more events are expected (meaning you
* should run the event loop again sometime in the future).
* - UV_RUN_NOWAIT: Poll for new events once but don't block if there are no
* pending events. Returns zero when done (no active handles
* or requests left), or non-zero if more events are expected (meaning you
* should run the event loop again sometime in the future).
*/
UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
uv_run函数的实现在src/unix/core.c中:
// src/unix/core.c
// 源码 304行
int uv_run(uv_loop_t* loop, uv_run_mode mode) {
int timeout;
int r;
// 在进入函数时首先检查该循环是否存货,
// 言外之意:是否有活跃的监听器或请求或者是否有关闭回调函数
// 这是uv__loop_alive函数的作用
r = uv__loop_alive(loop);
if (!r)
uv__update_time(loop);
// 如果事件循环是alive的,就进入这个while循环
while (r != 0 && loop->stop_flag == 0) {
// 这里表示每次while循环都是一个Tick
// 该宏相当于注释
UV_TICK_START(loop, mode);
uv__update_time(loop);
uv__run_timers(loop);
uv__run_pending(loop);
uv__run_idle(loop);
uv__run_prepare(loop);
timeout = 0;
if ((mode & UV_RUN_NOWAIT) == 0)
timeout = uv_backend_timeout(loop);
uv__io_poll(loop, timeout);
uv__run_check(loop);
uv__run_closing_handles(loop);
if (mode == UV_RUN_ONCE) {
/* UV_RUN_ONCE implies forward progess: at least one callback must have
* been invoked when it returns. uv__io_poll() can return without doing
* I/O (meaning: no callbacks) when its timeout expires - which means we
* have pending timers that satisfy the forward progress constraint.
*
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
* the check.
*/
uv__update_time(loop);
uv__run_timers(loop);
}
// 一次Tick结束之前再次检查事件循环是否仍是alive的
r = uv__loop_alive(loop);
// 下面同样是个注释,表示本次Tick结束了
UV_TICK_STOP(loop, mode);
if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))
break;
}
/* The if statement lets gcc compile it to a conditional store. Avoids
* dirtying a cache line.
*/
if (loop->stop_flag != 0)
loop->stop_flag = 0;
return r;
}
关于libuv,不必做过多介绍。从Node.js到Luvit,Rust,pyuv等无不体现libuv应用之广泛。
仍然是因“How does it work”的问题促使我去github扒源码。要说现在没有libuv的文档或者参考资料吗?当然有,只不过他们都没有进一步深入介绍,每份参考资料都仅仅停留在API基本使用上,并且还不完整,就像隔着一层窗户纸一样,这难以让人不产生一探究竟的冲动啊。
我想起之前写的那份“阅读Node.js源码”,在写那篇日志前我主要阅读的是多数调用V8相关的源码,而对libuv貌似并没有提及。Node.js的入口源码
node.cc
中有一段展示Node中是如何使用libuv的最最核心的代码,也是事件循环的起点:在Node的启动中有三处调用了libuv的API,我们得去libuv的源码中找找看,那些参数代表什么。官方文档中提到
uv.h
包含了libuv API,所以应该从uv.h入手:uv_run
函数的实现在src/unix/core.c
中:上面所用的
uv__loop_alive
函数定义在同一文件的292行:uv__has_active_handles
函数和uv__has_active_reqs
函数的实现在src/uv-common.h
中:下面是循环引用计数器的部分代码:
具体仍以宏定义形式实现的:
用于退出事件循环的函数是这样定义的:
Pending!
以上这些仅仅是libuv的一个初探,至于说能让不理解Node.js的事件循环运作原理的人大彻大悟,那是说笑了.因为在
uv_run
中调用的好多其他重要函数这里还没做介绍解释.下篇日志仍会从
uv_run
函数开始,详细而有条理的剖析事件循环的初始化,事件触发及监视器的工作流程,事件循环的退出.Reference