Análisis del código fuente de Libuv - 2. Introducción básica a Libuv

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.

    imagen.png

manejar【Mango】

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_tIntroducción de atributos
    • bucle es el bucle de eventos al que pertenece el identificador
    • type es el tipo de identificador, que está uv_##name##_testrechamente relacionado, y el uv_##name##_ttipo correspondiente es UV_##NAME##. En este caso, el tipo de subclase se handle->typepuede 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_tel 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_handlesformar 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_closingy todo. loop->closing_handles A través de este código, puede ver claramente que al cerrar la manija, solo necesita juzgar handle->next_closingsi 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_registeruv__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_unregisteruv__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_initInicialice 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
    复制代码

La imagen de abajo es del blog de Doumi. 1607609-63a6103f0fb911d6.webp

Supongo que te gusta

Origin juejin.im/post/7083845693302898695
Recomendado
Clasificación