今天继续看看 event loop 的核心循环, uv_run() , 可以查看以下网址
https://github.com/nodejs/node/blob/e46c680bf2b211bbd52cf959ca17ee98c7f657f5/deps/uv/src/win/core.c
int uv_run(uv_loop_t *loop, uv_run_mode mode) {
DWORD timeout;
int r;
int ran_pending;
r = uv__loop_alive(loop);
if (!r)
uv_update_time(loop);
while (r != 0 && loop->stop_flag == 0) {
uv_update_time(loop);
uv__run_timers(loop);
ran_pending = uv_process_reqs(loop);
uv_idle_invoke(loop);
uv_prepare_invoke(loop);
timeout = 0;
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
timeout = uv_backend_timeout(loop);
if (pGetQueuedCompletionStatusEx)
uv__poll(loop, timeout);
else
uv__poll_wine(loop, timeout);
/* Run one final update on the provider_idle_time in case uv__poll*
* returned because the timeout expired, but no events were received. This
* call will be ignored if the provider_entry_time was either never set (if
* the timeout == 0) or was already updated b/c an event was received.
*/
uv__metrics_update_idle_time(loop);
uv_check_invoke(loop);
uv_process_endgames(loop);
if (mode == UV_RUN_ONCE) {
/* UV_RUN_ONCE implies forward progress: 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__run_timers(loop);
}
r = uv__loop_alive(loop);
if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
break;
}
/* The if statement lets the compiler compile it to a conditional store.
* Avoids dirtying a cache line.
*/
if (loop->stop_flag != 0)
loop->stop_flag = 0;
return r;
}
今天继续看主要循环, 我们要来看
ran_pending = uv_process_reqs(loop);
这句代表 pending 阶段
INLINE static int uv_process_reqs(uv_loop_t* loop) {
uv_req_t* req;
uv_req_t* first;
uv_req_t* next;
if (loop->pending_reqs_tail == NULL)
return 0;
first = loop->pending_reqs_tail->next_req;
next = first;
loop->pending_reqs_tail = NULL;
while (next != NULL) {
req = next;
next = req->next_req != first ? req->next_req : NULL;
switch (req->type) {
case UV_READ:
DELEGATE_STREAM_REQ(loop, req, read, data);
break;
case UV_WRITE:
DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
break;
case UV_ACCEPT:
DELEGATE_STREAM_REQ(loop, req, accept, data);
break;
case UV_CONNECT:
DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
break;
case UV_SHUTDOWN:
/* Tcp shutdown requests don't come here. */
assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
uv_process_pipe_shutdown_req(
loop,
(uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
(uv_shutdown_t*) req);
break;
case UV_UDP_RECV:
uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
break;
case UV_UDP_SEND:
uv_process_udp_send_req(loop,
((uv_udp_send_t*) req)->handle,
(uv_udp_send_t*) req);
break;
case UV_WAKEUP:
uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
break;
case UV_SIGNAL_REQ:
uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
break;
case UV_POLL_REQ:
uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
break;
case UV_PROCESS_EXIT:
uv_process_proc_exit(loop, (uv_process_t*) req->data);
break;
case UV_FS_EVENT_REQ:
uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
break;
default:
assert(0);
}
}
return 1;
}
可以看到里面是标准的 IOCP pattern , 透过检测事件种类, 决定要使用哪种函数
除了定时触发事件, 会在 timer heap (前天内容) 处理, 和其余极少数事件, 其他全在这边处理。
而这里也是 Node 非同步 schedule 的核心实践。
我们随意挑一种事件的处理看看
查看 uv_process_async_wakeup_req
void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
uv_req_t* req) {
assert(handle->type == UV_ASYNC);
assert(req->type == UV_WAKEUP);
handle->async_sent = 0;
if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*)handle);
} else if (handle->async_cb != NULL) {
handle->async_cb(handle);
}
}
可以看到基本上就是根据事件触发对应的 callback , 而如果还需要後续的 IO 处理, 则会调用 WSAXXX 等等来下达非阻塞的 IO 命令。
我们用一个简化的流程来描述 libuv 的事件循环
补充 : 还有一个 endgame queue , pending 做完的事件会被推进该 queue , 在 endgame 阶段关闭。
基於篇幅与主题, 我就不去深究其细节, 明天赶紧进入 node 的 thread pool 篇
明天见 !
>>: [Day24] Esp32 + LINE - (程序码讲解)
前面讲了那麽多关於Basic Widget今天我们就用其中一个来写个小范例吧! 我们用BottomN...
本日来介绍一下 solidity 的控制流程。 学任何语言基本上都需要条件判断式,那就稍微简单介绍一...
耶~~~终於迈入第十天,完成了三分之一,今天要来讲文字方块,普遍常会看到的用法会在输入号密码的时候,...
前两天讲得订单不知道大家还有没有印象? 在产生订单之前还有个很常用到的功能----购物车 现代电商没...
这篇文章我们将说来谈谈《 Patterns of Enterprise Application Ar...