libuv学习笔记(6)
uv_prepare_t、uv_idel_t、uv_check_t的数据结构与相关API
三种监视器(watcher),每次循环迭代都会调用它的回调函数
数据结构
typedef struct uv_prepare_s uv_prepare_t;
typedef struct uv_check_s uv_check_t;
typedef struct uv_idle_s uv_idle_t;
struct uv_prepare_s
{
UV_HANDLE_FIELDS//uv_handle_t的数据,此处不再展开,请参考之前的内容
//UV_PREPARE_PRIVATE_FIELDS展开如下:
uv_prepare_t* prepare_prev;//指向上一个
uv_prepare_t* prepare_next;//指向下一个
uv_prepare_cb prepare_cb;//回调函数
};
三种watcher的结构基本一致,只是其中的指针类型以及回调函数类型不同
相关API (以uv_prepare_t的相关函数为例,另外两种的处理函数流程基本一致)
1.初始化函数,导出函数,在uv.h中声明,loop-watcher.c中通过宏定义
基本的handle初始化流程,没有什么特殊的处理。
int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* handle)
{
//uv__handle_init(loop, (uv_handle_t*) handle, UV_PREPARE);展开:
do {
(h)->loop = (loop);
(h)->type = (UV_PREPARE);
(h)->flags = UV__HANDLE_REF; /* 设为引用状态. */
//将handle添加到loop的handle队列
QUEUE_INSERT_TAIL(&(loop)->handle_queue, &(handle)->handle_queue);
//uv__handle_platform_init(h); 展开
((handle)->u.fd = -1);
}
while (0)
return 0;
}
2.开始(激活),导出函数,在uv.h中声明,loop-watcher.c中通过宏定义
int uv_prepare_start(uv_prepare_t* handle, uv_prepare_cb cb)
{
uv_loop_t* loop = handle->loop;
uv_prepare_t* old_head;
assert(handle->type == UV_PREPARE);
//如果已经是激活状态,直接返回
if (uv__is_active(handle))
return 0;
//没有设置回调函数,返回错误
if (cb == NULL)
return UV_EINVAL;
//将本handle插入到loop的prepare_handles列表的表头
old_head = loop->prepare_handles;
handle->prepare_next = old_head;
handle->prepare_prev = NULL;
if (old_head)
{
old_head->prepare_prev = handle;
}
loop->prepare_handles = handle;
handle->prepare_cb = cb;
//uv__handle_start(handle); 展开如下
do {
assert(((handle)->flags & UV__HANDLE_CLOSING) == 0);
if (((handle)->flags & UV__HANDLE_ACTIVE) != 0) break;
(handle)->flags |= UV__HANDLE_ACTIVE;//设为active状态
//如果同时处于引用状态,loop的活动handle计数加一
if (((handle)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(handle);
}
while (0);
return 0;
}
3.停止handle,导出函数,在uv.h中声明,loop-watcher.c中通过宏定义
int uv_prepare_stop(uv_prepare_t* handle)
{
uv_loop_t* loop = handle->loop;
assert(handle->type == UV_PREPARE);
if (!uv__is_active(handle))
return 0;
/* 如果本handle为loop prepare_handle列表的第一个元素,更新loop的prepare_handles指针 */
if (loop->prepare_handles == handle) {
loop->prepare_handles = handle->prepare_next;
}
/* 如果loop的下一个prepare_handle是本handle,更新 */
if (loop->next_prepare_handle == handle) {
loop->next_prepare_handle = handle->prepare_next;
}
//从列表中删除本handle
if (handle->prepare_prev) {
handle->prepare_prev->prepare_next = handle->prepare_next;
}
if (handle->prepare_next) {
handle->prepare_next->prepare_prev = handle->prepare_prev;
}
//uv__handle_stop(handle); 展开如下:
do {
assert(((h)->flags & UV__HANDLE_CLOSING) == 0);
if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break;
(h)->flags &= ~UV__HANDLE_ACTIVE;//去掉active标志
//如果同时在引用状态,loop的活动handle计数减一
if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h);
}
while (0);
return 0;
}
关闭操作(通过uv_close)
在uv_close中处理如下
...
case UV_PREPARE:
uv_prepare_stop((uv_prepare_t*)handle);
uv__handle_closing(handle);
uv_want_endgame(loop, handle);
return;
...
通过uv_want_endgame将handle插入到loop->endgame_handles的列表头,接着在uv_run中会调用uv_process_endgames处理所有的需要关闭的handle
...
case UV_PREPARE:
case UV_CHECK:
case UV_IDLE:
uv_loop_watcher_endgame(loop, handle);
break;
...
通过代码可知,三种监视器的关闭都是调用的uv_loop_watcher_endgame:
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle)
{
if (handle->flags & UV__HANDLE_CLOSING)
{
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;//状态变为UV__HANDLE_CLOSED
//uv__handle_close(handle);展开如下:
do {
QUEUE_REMOVE(&(handle)->handle_queue);//从队列中移除
uv__active_handle_rm((uv_handle_t*) (handle));//handle计数递减
(handle)->flags |= UV_HANDLE_CLOSED;
//调用回调函数
if ((handle)->close_cb)
(handle)->close_cb((uv_handle_t*) (handle));
} while (0)
}
}
4.循环迭代中的调用(uv_run)
void uv_prepare_invoke(uv_loop_t* loop) {
uv_prepare_t* handle;
(loop)->next_prepare_handle = (loop)->prepare_handles;
//循环调用每一个uv_prepare_t的回调函数
while ((loop)->next_prepare_handle != NULL) {
handle = (loop)->next_prepare_handle;
(loop)->next_prepare_handle = handle->prepare_next;
handle->prepare_cb(handle);
}
}
三种watcher的结构以及处理流程基本都一致,相关函数都是通过loop-watcher.c中的UV_LOOP_WATCHER_DEFINE宏定义的。三种watcher的区别在于:
1.在循环迭代中的调用顺序不同:
idle(空转)在处理完上个迭代获取的请求之后调用
prepare紧接着idle之后调用
check在轮询之后调用
2.idle会影响loop i/o轮询的超时设置,当有idle时,超时时间为0。