uv_fs_*
uv_fs_*这一系列的函数基本是一致的,它们的逻辑大概是如下:
1 | //x代表一种操作open、write等 |
INIT
INIT这个宏定义函数没有特别的地方,就是把req初始化,该置0的置0。
POST
其实现如下:
1 |
|
这里通过有无回调函数来决定调用同步版本还是异步版本。
http://docs.libuv.org/en/v1.x/fs.html
libuv provides a wide variety of cross-platform sync and async file system operations. All functions defined in this document take a callback, which is allowed to be NULL. If the callback is NULL the request is completed synchronously, otherwise it will be performed asynchronously.
uv__fs_work这个函数就是文件操作的封装,所有的文件操作都通过这个函数来完成,即使是异步,最终也要在别的线程中同步执行这个函数。
uv__fs_done这个函数会调用用户给的回调函数,这个函数会在uv_run中的is_poll函数中得到执行。
uv__work_submit函数的实现是这样的:
1 | void uv__work_submit(uv_loop_t* loop,struct uv__work* w, |
uv_once(&once, init_once);是初始化多个线程,我在我的第三篇文章中有介绍。不过当时对于子线程运行的worker函数没有提及,work函数大概是这样的:
1 | static void worker(void* arg) { |
我去掉了对于slow_io的处理,大致是这样一个过程。
一开始线程会卡在uv_cond_wait这里,直到被uv_cond_signal唤醒,如果唤醒时wq队列中有任务,它就会执行任务,w->work(w)也就是调用uv__fs_work。然后把w放入loop->wq(为了uv__fs_done的执行)。
uv_async_send调用让loop->wq_async可读,主线程就从uv_run中的uv__io_poll的epoll_pwait中醒来,wq_async的回调函数会遍历loop->wq执行w->done。(我的第四篇文章有讲这一部分的详细内容)
谁来触发uv_cond_signal唤醒子线程呢?
🥣uv__work_submit中的post函数:
1 | uv_mutex_lock(&mutex); |
我再次省略了slow_io的部分,因为它们只是特殊处理。
该函数有空闲的线程就唤醒,不然就阻塞该线程。