很久之前看的libuv源码的时候记录的一些乱七八糟的东西ORZ。 强烈推荐直接看参考链接搞清楚文件IO和网络IO怎么实现的就行,我的记录大概只有我自己能看懂。
1 设计理念
libuv uses a thread pool to make asynchronous file I/O operations possible, but network I/O is always performed in a single thread, each loop’s thread.
Threads are used internally to fake the asynchronous nature of all of the system calls.
2 事件循环
一个死循环执行多个phase
,每一个phase
检查是否有事件发生,其中最重要的phase
就是uv_poll_io
这个阶段负责调用比如epoll
这样的多路复用api监听事件, 有对应的事件发生则执行IO操作然后执行回调(比如epoll -> read -> read_cb, 记住epoll不执行实际的IO, 只是监听), 在回调中可能又会添加新的事件保证事件循环不断的进行下去。主要流程为: 执行IO -> 执行回调 -> 执行IO -> 执行回调 …
注意网络IO和文件IO是不太一致的,后者利用了线程池。
在网络IO中执行IO的任务为uv__io_t
中的cb
,执行位置为uv_poll_io
。
在文件IO中执行的任务为uv__work
的work
,执行位置为线程池。
两种任务的回调都在uv_poll_io
中执行。
备注: epoll_pwait
设置signal
然后wait
可能被信号唤醒而不是因为有事件发生
2.1 uv__io_poll
实际执行poll事件的函数。以epoll为例,如果有事件发生就调用对应的io_watcher的cb函数即可
2.2 网络IO流程
https://blog.butonly.com/posts/node.js/libuv/6-libuv-stream/
uv_tcp_init
-> uv__stream_init
(初始化stream
)
-> uv__io_init
(初始化uv__io_t
: 赋值stream
中的uv__io_t
的cb
(uv__stream_io
)实际任务)
-> uv_listen
( uv_tcp_listen
)
-> uv__io_start
添加IO观察者uv__io_t
到loop->watchers
中
-> uv_poll_io
中有事件发生执行uv__stream_io
, uv__stream_io
执行对应的read
, connect
, write
操作后执行对应的回调read_cb
等
1 | // io_watcher的cb,会根据stream当前状态调用实际的IO任务,比如uv__read |
1 | // 添加监听IO对象 |
2.3 文件IO流程
2.3.1 线程池
初始化4个线程, 全部执行worker
函数worker
函数使用信号量进行休眠等待有任务提交时苏醒,苏醒后从work queue
中取出任务执行,用户可以通过api提交任务到work queue
同时唤醒正在休眠的线程。
2.3.2 提交任务
https://github.com/libuv/help/issues/62
uv_fs__t
是文件系统请求,内部api比如uv_fs_read
会产生uv_work_submit
从而使用线程池处理, uv_work
代表需要线程池处理的任务uv_work->work
是要执行的任务,具体流程如下
uv_fs_open
(初始化uv_fs__t
:init
->path
, 然後提交任務:post
)
-> uv__work_submit
(初始化uv__work
,赋值其中的work
(uv__fs_work
)和done
(uv__fs_done
)属性,提交任务)
-> uv_cond_signal
(唤醒工作线程)
-> w->work(w)
执行实际的IO操作(uv__fs_work
, uv__fs_work
中会根据uv_fs_t
中的fs_type
映射到实际的操作系统API)
-> uv_async_send
-> uv__async_send
(写字符串到async_wfd
, uv__io_poll
会检查所有的 file description
使用epoll_wait
所以会知道文件操作完成)
-> uv__io_poll
中执行回调 w->cb
(也就是uv__async_io
,和stream中类似也是提前设置的,stream中叫uv__stream_io
)
-> (uv__work_done
-> uv__fs_done
)
1 | static void uv__fs_work(struct uv__work* w) { |
3 数据结构
1 | struct uv_loop_s { |
两种IO请求
1 | struct uv__io_s { |
1 | struct uv__work { |
1 | typedef void* QUEUE[2] |
参考
https://zhuanlan.zhihu.com/p/83765851
https://blog.butonly.com/posts/node.js/libuv/6-libuv-stream/
https://github.com/libuv/help/issues/62
https://blog.butonly.com/posts/node.js/libuv/7-libuv-async/