Introduction to Libuv
-
Libuv is a cross-platform event-driven asynchronous io library. But the functions he provides are not only io, including processes, threads, signals, timers, inter-process communication, etc.
handle【Handle】
- A handle represents a long-lived object capable of performing a specific operation while active
- All handles in Libuv need to be initialized, which will be called during initialization to
uv_xxx_init
indicatexxx
the type of handle - Handle types in Libuv
uv_loop_t
--- event loopuv_handle_t
--- base handleuv_req_t
--- Basic requestuv_timer_t
--- Timer handleuv_prepare_t
--- prepare handleuv_check_t
--- check handleuv_idle_t
--- Idle handleuv_async_t
--- Asynchronous handleuv_poll_t
--- poll handleuv_signal_t
--- Signal handleuv_process_t
--- Process handleuv_stream_t
--- stream handleuv_tcp_t
--- TCP handleuv_pipe_t
--- Pipe handleuv_tty_t
--- TTY handleuv_udp_t
--- UDP handleuv_fs_event_t
--- FS Event handleuv_fs_poll_t
--- FS Poll handle
uv_handle_t [basic handle]
- abstract base class for all handles
- source code
struct uv_handle_s { UV_HANDLE_FIELDS }; #define UV_HANDLE_FIELDS \ void* data; /* 公有数据,指向用户自定义数据,libuv不使用该成员 */ \ \ /* 只读数据 */ \ uv_loop_t* loop; /* 指向依赖的循环 */ \ uv_handle_type type; /* 句柄类型 */ \ /* private */ \ uv_close_cb close_cb; /* 句柄关闭时的回调函数 */ \ void* handle_queue[2]; /* 句柄队列指针,分别指向上一个和下一个 */ \ union { \ int fd; \ void* reserved[4]; \ } u; \ UV_HANDLE_PRIVATE_FIELDS \ #define UV_HANDLE_PRIVATE_FIELDS \ uv_handle_t* next_closing; /* 指向下一个需要关闭的handle */ \ unsigned int flags; /* 状态标记,比如引用、关闭、正在关闭、激活等状态 */ \ 复制代码
uv_handle_t
Attribute introduction- loop is the event loop to which the handle belongs
- type is the handle type, which is
uv_##name##_t
strongly related, and the correspondinguv_##name##_t
type isUV_##NAME##
. In this case, the type of the subclass canhandle->type
be easily determined .uv_handle_t
- The callback executed when the close_cb handle is closed, the input parameter is
uv_handle_t
the pointer - handle_queue handle queue pointer
- u.fd file descriptor
- next_closing The next handle that needs to be closed, which can
loop->closing_handles
form a linked list structure, which is convenient for deletion
void uv__make_close_pending(uv_handle_t* handle) { assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->next_closing = handle->loop->closing_handles; handle->loop->closing_handles = handle; } 复制代码
- When initialized, it will be empty
handle->next_closing
and all.loop->closing_handles
Through this code, you can clearly see that when closing the handle, you only need to judgehandle->next_closing
whether it is null to know whether all the handles have been closed. - flags are flags for the handle state.
uv_##name##_t 的实现
在这里我们以uv_poll_s
结构体为例,来解读一下libuv如何使用宏实现的类似继承的操作:
struct uv_poll_s {
UV_HANDLE_FIELDS
uv_poll_cb poll_cb;
UV_POLL_PRIVATE_FIELDS
};
复制代码
在uv_poll_s
数据结构中,第一个使用的宏便是UV_HANDLE_FIELDS
宏,其次才为uv_poll_s
的私有宏。所有的uv_##name##_t
均包含了uv_handle_t
的结构体变量,所以任何的uv_##name##_t
都可以转换为uv_handle_t
。
handle 的基本操作
uv__handle_init
初始化 handle 的类型,设置 REF 标记,插入 handle 队列#define uv__handle_init(loop_, h, type_) \ do { \ (h)->loop = (loop_); \ (h)->type = (type_); \ (h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \ /*所有的 handle 都是由 loop -> handle_queue 来同一管理的*/ QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \ uv__handle_platform_init(h); \ } \ while (0) #if defined(_WIN32) # define uv__handle_platform_init(h) ((h)->u.fd = -1) #else # define uv__handle_platform_init(h) ((h)->next_closing = NULL) #endif 复制代码
uv__handle_start
设置标记 handle 为 ACTIVE,如果设置了 REF 标记,则 active handle 的个数加一,active handle 数会影响事件循环的退出#define uv__handle_start(h) \ do { \ if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \ (h)->flags |= UV_HANDLE_ACTIVE; \ if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h); \ } \ while (0) #define uv__active_handle_add(h) \ do { \ (h)->loop->active_handles++; \ } \ while (0) 复制代码
uv__handle_stop
uv__handle_stop 和 uv__handle_start 相反#define uv__handle_stop(h) \ do { \ if (((h)->flags & UV_HANDLE_ACTIVE) == 0) break; \ (h)->flags &= ~UV_HANDLE_ACTIVE; \ if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_rm(h); \ } \ while (0) 复制代码
uv__handle_ref
uv__handle_ref 标记 handle 为 REF 状态,如果 handle 是 ACTIVE 状态,则 active handle 数加一#define uv__handle_ref(h) \ do { /* 如果已经是引用状态,返回 */ \ if (((h)->flags & UV_HANDLE_REF) != 0) break; \ /* 设为引用状态 */ (h)->flags |= UV_HANDLE_REF; \ /* 正在关闭,直接返回 */ if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \ /* 激活状态下,将循环的active_handles加一 */ if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \ } \ while (0) 复制代码
uv__handle_unref
uv__handle_unref 去掉 handle 的 REF 状态,如果 handle 是 ACTIVE 状态,则 active handle 数减一#define uv__handle_unref(h) \ do { \ if (((h)->flags & UV_HANDLE_REF) == 0) break; \ /* 去掉UV__HANDLE_REF标记 */ (h)->flags &= ~UV_HANDLE_REF; \ if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \ if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \ } \ while (0) 复制代码
- libuv 中 handle 有 REF 和 ACTIVE 两个状态。当一个 handle 调用 xxx_init 函数的时候, 他首先被打上 REF 标记,并且插入 loop->handle 队列。当 handle 调用 xxx_start 函 数的时候,他首先被打上 ACTIVE 标记,并且记录 active handle 的个数加一。只有 ACTIVE 状态的 handle 才会影响事件循环的退出
请求【request】
- 请求代表着(通常是)短期的操作。 这些操作可以通过一个句柄执行: 写请求用于在句柄上写数据;或是独立不需要句柄的:getaddrinfo 请求 不需要句柄,它们直接在循环上运行
Basic operation of request
uv__req_register
uv__req_register records the number of requests (requests) plus one#define uv__req_register(loop, req) \ do { \ (loop)->active_reqs.count++; \ } \ while (0) 复制代码
uv__req_unregister
uv__req_unregister records the number of requests minus one#define uv__req_unregister(loop, req) \ do { \ assert(uv__has_active_reqs(loop)); \ (loop)->active_reqs.count--; \ } \ while (0) 复制代码
uv__req_init
Initialize the type of request, record the number of requests#define uv__req_init(loop, req, typ) \ do { \ UV_REQ_INIT(req, typ); \ uv__req_register(loop, req); \ } \ while (0) #if defined(_WIN32) # define UV_REQ_INIT(req, typ) \ do { \ (req)->type = (typ); \ (req)->u.io.overlapped.Internal = 0; /* SET_REQ_SUCCESS() */ \ } \ while (0) #else # define UV_REQ_INIT(req, typ) \ do { \ (req)->type = (typ); \ } \ while (0) #endif 复制代码