Introducción a Libuv
-
Libuv es una biblioteca de E/S asíncrona basada en eventos multiplataforma. Pero las funciones que proporciona no son solo io, incluidos procesos, hilos, señales, temporizadores, comunicación entre procesos, etc.
manejar【Mango】
- Un identificador representa un objeto de larga duración capaz de realizar una operación específica mientras está activo
- Todos los identificadores en Libuv deben inicializarse, lo que se llamará durante la inicialización para
uv_xxx_init
indicarxxx
el tipo de identificador - Tipos de manijas en Libuv
uv_loop_t
--- bucle de eventosuv_handle_t
--- manija baseuv_req_t
--- Solicitud básicauv_timer_t
--- Manija del temporizadoruv_prepare_t
--- preparar mangouv_check_t
--- verifique la manijauv_idle_t
--- Mango inactivouv_async_t
--- Mango asíncronouv_poll_t
--- identificador de encuestauv_signal_t
--- Mango de señaluv_process_t
--- Manejador de procesouv_stream_t
--- identificador de flujouv_tcp_t
--- identificador TCPuv_pipe_t
--- Mango de tubouv_tty_t
--- Mango TTYuv_udp_t
--- identificador UDPuv_fs_event_t
--- Controlador de eventos FSuv_fs_poll_t
--- Identificador de encuesta FS
uv_handle_t [manejador básico]
- clase base abstracta para todos los identificadores
- código fuente
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
Introducción de atributos- bucle es el bucle de eventos al que pertenece el identificador
- type es el tipo de identificador, que está
uv_##name##_t
estrechamente relacionado, y eluv_##name##_t
tipo correspondiente esUV_##NAME##
. En este caso, el tipo de subclase sehandle->type
puede determinar fácilmente .uv_handle_t
- La devolución de llamada se ejecuta cuando se cierra el identificador close_cb, el parámetro de entrada es
uv_handle_t
el puntero - handle_queue maneja el puntero de la cola
- descriptor de archivo u.fd
- next_closing El siguiente identificador que debe cerrarse, que puede
loop->closing_handles
formar una estructura de lista enlazada, que es conveniente para la eliminación
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; } 复制代码
- Cuando se inicialice, estará vacío
handle->next_closing
y todo.loop->closing_handles
A través de este código, puede ver claramente que al cerrar la manija, solo necesita juzgarhandle->next_closing
si es nulo para saber si todas las manijas se han cerrado. - las banderas son banderas para el estado del identificador.
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 请求 不需要句柄,它们直接在循环上运行
Funcionamiento básico de la solicitud
uv__req_register
uv__req_register registra el número de solicitudes (requests) más uno#define uv__req_register(loop, req) \ do { \ (loop)->active_reqs.count++; \ } \ while (0) 复制代码
uv__req_unregister
uv__req_unregister registra el número de solicitudes menos uno#define uv__req_unregister(loop, req) \ do { \ assert(uv__has_active_reqs(loop)); \ (loop)->active_reqs.count--; \ } \ while (0) 复制代码
uv__req_init
Inicialice el tipo de solicitud, registre el número de solicitudes#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 复制代码